You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2021/05/03 05:28:58 UTC
[tomee-jakarta] 06/06: TCK fixes reapplied
This is an automated email from the ASF dual-hosted git repository.
dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-jakarta.git
commit 9a737a0e805151842209d6704d77d136970ec964
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun May 2 22:01:52 2021 -0700
TCK fixes reapplied
---
.../cxf/jaxrs/provider/AbstractJAXBProvider.java | 14 +++-
.../apache/cxf/jaxrs/provider/ProviderFactory.java | 98 ++++++++++++++++++++--
.../org/apache/cxf/jaxrs/utils/InjectionUtils.java | 50 ++++++-----
.../org/apache/cxf/jaxrs/utils/JAXRSUtils.java | 18 +++-
4 files changed, 141 insertions(+), 39 deletions(-)
diff --git a/transform/src/patch/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java b/transform/src/patch/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java
index f2bee17..b94760a 100644
--- a/transform/src/patch/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java
+++ b/transform/src/patch/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java
@@ -42,6 +42,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NoContentException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.ext.ContextResolver;
@@ -68,6 +69,8 @@ import org.w3c.dom.Element;
import org.xml.sax.helpers.DefaultHandler;
+import com.ctc.wstx.exc.WstxEOFException;
+
import org.apache.cxf.annotations.SchemaValidation;
import org.apache.cxf.common.jaxb.JAXBUtils;
import org.apache.cxf.common.util.PackageUtils;
@@ -719,7 +722,12 @@ public abstract class AbstractJAXBProvider<T> extends AbstractConfigurableProvid
return sb;
}
- protected static void handleExceptionEnd(Throwable t, String message, boolean read) {
+ protected static void handleExceptionEnd(Throwable t, String message, boolean read) throws NoContentException {
+ if (t instanceof WstxEOFException && t.getMessage().startsWith("Unexpected EOF in prolog")){
+ String noContent = new org.apache.cxf.common.i18n.Message("EMPTY_BODY", BUNDLE).toString();
+ LOG.warning(noContent);
+ throw new NoContentException(noContent);
+ }
Response.Status status = read
? Response.Status.BAD_REQUEST : Response.Status.INTERNAL_SERVER_ERROR;
Response r = JAXRSUtils.toResponseBuilder(status)
@@ -728,7 +736,7 @@ public abstract class AbstractJAXBProvider<T> extends AbstractConfigurableProvid
: ExceptionUtils.toInternalServerErrorException(t, r);
}
- protected void handleJAXBException(JAXBException e, boolean read) {
+ protected void handleJAXBException(JAXBException e, boolean read) throws NoContentException {
StringBuilder sb = handleExceptionStart(e);
Throwable linked = e.getLinkedException();
if (linked != null && linked.getMessage() != null) {
@@ -753,7 +761,7 @@ public abstract class AbstractJAXBProvider<T> extends AbstractConfigurableProvid
handleExceptionEnd(t, message, read);
}
- protected void handleXMLStreamException(XMLStreamException e, boolean read) {
+ protected void handleXMLStreamException(XMLStreamException e, boolean read) throws NoContentException {
StringBuilder sb = handleExceptionStart(e);
handleExceptionEnd(e, sb.toString(), read);
}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java b/transform/src/patch/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
index c8a0aff..65c417c 100644
--- a/transform/src/patch/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
+++ b/transform/src/patch/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
@@ -39,6 +39,7 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
+import javax.annotation.Priority;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Configuration;
@@ -77,6 +78,8 @@ import org.apache.cxf.jaxrs.utils.ResourceUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageUtils;
+import static javax.ws.rs.Priorities.USER;
+
public abstract class ProviderFactory {
public static final String DEFAULT_FILTER_NAME_BINDING = "org.apache.cxf.filter.binding";
public static final String PROVIDER_SELECTION_PROPERTY_CHANGED = "provider.selection.property.changed";
@@ -662,6 +665,7 @@ public abstract class ProviderFactory {
sortReaders();
sortWriters();
sortContextResolvers();
+ sortParamConverters();
mapInterceptorFilters(readerInterceptors, readInts, ReaderInterceptor.class, true);
mapInterceptorFilters(writerInterceptors, writeInts, WriterInterceptor.class, true);
@@ -783,7 +787,9 @@ public abstract class ProviderFactory {
contextResolvers.sort(new ContextResolverComparator());
}
-
+ private void sortParamConverters() {
+ paramConverters.sort(new ParamConverterComparator());
+ }
@@ -853,9 +859,12 @@ public abstract class ProviderFactory {
setProviders(true, false, userProviders.toArray());
}
- private static class MessageBodyReaderComparator
+ static class MessageBodyReaderComparator
implements Comparator<ProviderInfo<MessageBodyReader<?>>> {
+ private final GenericArgumentComparator classComparator =
+ new GenericArgumentComparator(MessageBodyReader.class);
+
public int compare(ProviderInfo<MessageBodyReader<?>> p1,
ProviderInfo<MessageBodyReader<?>> p2) {
MessageBodyReader<?> e1 = p1.getProvider();
@@ -870,7 +879,10 @@ public abstract class ProviderFactory {
if (result != 0) {
return result;
}
- result = compareClasses(e1, e2);
+
+ final Class<?> class1 = ClassHelper.getRealClass(e1);
+ final Class<?> class2 = ClassHelper.getRealClass(e2);
+ result = classComparator.compare(class1, class2);
if (result != 0) {
return result;
}
@@ -878,19 +890,30 @@ public abstract class ProviderFactory {
if (result != 0) {
return result;
}
- return comparePriorityStatus(p1.getProvider().getClass(), p2.getProvider().getClass());
+
+ result = comparePriorityStatus(p1.getProvider().getClass(), p2.getProvider().getClass());
+ if (result != 0) {
+ return result;
+ }
+
+ return p1.getProvider().getClass().getName().compareTo(p2.getProvider().getClass().getName());
}
}
- private static class MessageBodyWriterComparator
+ static class MessageBodyWriterComparator
implements Comparator<ProviderInfo<MessageBodyWriter<?>>> {
+ private final GenericArgumentComparator classComparator =
+ new GenericArgumentComparator(MessageBodyWriter.class);
+
public int compare(ProviderInfo<MessageBodyWriter<?>> p1,
ProviderInfo<MessageBodyWriter<?>> p2) {
MessageBodyWriter<?> e1 = p1.getProvider();
MessageBodyWriter<?> e2 = p2.getProvider();
- int result = compareClasses(e1, e2);
+ final Class<?> class1 = ClassHelper.getRealClass(e1);
+ final Class<?> class2 = ClassHelper.getRealClass(e2);
+ int result = classComparator.compare(class1, class2);
if (result != 0) {
return result;
}
@@ -903,13 +926,18 @@ public abstract class ProviderFactory {
if (result != 0) {
return result;
}
-
+
result = compareCustomStatus(p1, p2);
if (result != 0) {
return result;
}
- return comparePriorityStatus(p1.getProvider().getClass(), p2.getProvider().getClass());
+ result = comparePriorityStatus(p1.getProvider().getClass(), p2.getProvider().getClass());
+ if (result != 0) {
+ return result;
+ }
+
+ return p1.getProvider().getClass().getName().compareTo(p2.getProvider().getClass().getName());
}
}
@@ -1136,7 +1164,7 @@ public abstract class ProviderFactory {
// superclass should go last
return -1;
}
-
+
// there is no relation between the types returned by the providers
return 0;
}
@@ -1495,4 +1523,56 @@ public abstract class ProviderFactory {
writerInterceptors = sortedWriterInterceptors;
}
+ protected static class ParamConverterComparator implements Comparator<ProviderInfo<ParamConverterProvider>> {
+
+ @Override
+ public int compare(final ProviderInfo<ParamConverterProvider> a,
+ final ProviderInfo<ParamConverterProvider> b) {
+
+ /*
+ * Primary sort. Also takes care of sorting custom
+ * converters from system converters due to priority
+ * defaults
+ */
+ int result = sortByPriority(a, b);
+
+ /*
+ * Secondary sort as this list *will* change order
+ * once in a while between jvm restarts, which can
+ * have frustrating consequences for users who are
+ * expecting no change in behavior as they aren't
+ * changing their code.
+ */
+ if (result == 0) {
+ result = sortByClassName(a, b);
+ }
+
+ return result;
+ }
+
+ public int sortByPriority(final ProviderInfo<ParamConverterProvider> a,
+ final ProviderInfo<ParamConverterProvider> b) {
+ final int aPriority = getPriority(a);
+ final int bPriority = getPriority(b);
+
+ // Sort ascending as the priority with the lowest number wins
+ return Integer.compare(aPriority, bPriority);
+ }
+
+ public int sortByClassName(final ProviderInfo<ParamConverterProvider> a,
+ final ProviderInfo<ParamConverterProvider> b) {
+
+ // Sort ascending as the priority with the lowest number wins
+ return a.getProvider().getClass().getName().compareTo(b.getProvider().getClass().getName());
+ }
+
+ private int getPriority(final ProviderInfo<ParamConverterProvider> providerInfo) {
+ final Priority priority = providerInfo.getProvider().getClass().getAnnotation(Priority.class);
+ if (priority!=null) {
+ return priority.value();
+ }
+ return providerInfo.isCustom() ? USER : USER + 1000;
+ }
+ }
+
}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java b/transform/src/patch/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
index 5543093..dca074a 100644
--- a/transform/src/patch/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
+++ b/transform/src/patch/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
@@ -53,20 +53,20 @@ import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Application;
-import javax.ws.rs.core.GenericEntity;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.PathSegment;
-import javax.ws.rs.core.Request;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.SecurityContext;
-import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.ext.ContextResolver;
-import javax.ws.rs.ext.ParamConverter;
-import javax.ws.rs.ext.Providers;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.GenericEntity;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.PathSegment;
+import jakarta.ws.rs.core.Request;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.SecurityContext;
+import jakarta.ws.rs.core.UriInfo;
+import jakarta.ws.rs.ext.ContextResolver;
+import jakarta.ws.rs.ext.ParamConverter;
+import jakarta.ws.rs.ext.Providers;
import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.i18n.BundleUtils;
@@ -537,15 +537,19 @@ public final class InjectionUtils {
}
private static RuntimeException createParamConversionException(ParameterType pType, Exception ex) {
- //
- // For path, query & matrix parameters this is 404,
- // for others 400...
- //
- if (pType == ParameterType.PATH || pType == ParameterType.QUERY
- || pType == ParameterType.MATRIX) {
- return ExceptionUtils.toNotFoundException(ex, null);
- }
- return ExceptionUtils.toBadRequestException(ex, null);
+ /*
+ * Loosely related to the following section of the Jakarta REST specification:
+ *
+ * At least one of the acceptable response entity body media types is a supported output data
+ * format (see Section 3.5). If no methods support one of the acceptable response entity body
+ * media types an implementation MUST generate a NotAcceptableException (406 status)
+ * and no entity.
+ *
+ * Tested by:
+ * com.sun.ts.tests.jaxrs.ee.rs.ext.paramconverter.JAXRSClient
+ * atomicIntegerIsLazyDeployableAndThrowsErrorTest_from_standalone
+ */
+ return ExceptionUtils.toNotAcceptableException(ex, null);
}
public static <T> Optional<ParamConverter<T>> getParamConverter(Class<T> pClass,
diff --git a/transform/src/patch/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java b/transform/src/patch/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
index f264b48..3f0073a 100644
--- a/transform/src/patch/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
+++ b/transform/src/patch/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
@@ -47,6 +47,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import javax.activation.DataSource;
import javax.ws.rs.ClientErrorException;
import javax.ws.rs.Consumes;
import javax.ws.rs.HttpMethod;
@@ -65,6 +66,7 @@ import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NoContentException;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
@@ -164,11 +166,11 @@ public final class JAXRSUtils {
private static final ResourceBundle BUNDLE = BundleUtils.getBundle(JAXRSUtils.class);
private static final String PATH_SEGMENT_SEP = "/";
private static final String REPORT_FAULT_MESSAGE_PROPERTY = "org.apache.cxf.jaxrs.report-fault-message";
- private static final String NO_CONTENT_EXCEPTION = "javax.ws.rs.core.NoContentException";
+ private static final String NO_CONTENT_EXCEPTION = NoContentException.class.getName();
private static final String HTTP_CHARSET_PARAM = "charset";
private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0];
private static final Set<Class<?>> STREAMING_OUT_TYPES = new HashSet<>(
- Arrays.asList(InputStream.class, Reader.class, StreamingOutput.class));
+ Arrays.asList(InputStream.class, Reader.class, StreamingOutput.class, DataSource.class));
private JAXRSUtils() {
}
@@ -394,6 +396,8 @@ public final class JAXRSUtils {
int methodMatched = 0;
int consumeMatched = 0;
+ boolean resourceMethodsAdded = false;
+ boolean generateOptionsResponse = false;
List<OperationResourceInfo> finalPathSubresources = null;
for (Map.Entry<ClassResourceInfo, MultivaluedMap<String, String>> rEntry : matchedResources.entrySet()) {
ClassResourceInfo resource = rEntry.getKey();
@@ -433,18 +437,21 @@ public final class JAXRSUtils {
if (matchProduceTypes(acceptType, ori)) {
candidateList.put(ori, map);
added = true;
+ resourceMethodsAdded = true;
break;
}
}
}
//CHECKSTYLE:ON
+ } else if ("OPTIONS".equalsIgnoreCase(httpMethod)) {
+ generateOptionsResponse = true;
}
}
}
LOG.fine(matchMessageLogSupplier(ori, path, httpMethod, requestType, acceptContentTypes, added));
}
}
- if (finalPathSubresources != null && pathMatched > 0
+ if (finalPathSubresources != null && (resourceMethodsAdded || generateOptionsResponse)
&& !MessageUtils.getContextualBoolean(message, KEEP_SUBRESOURCE_CANDIDATES, false)) {
for (OperationResourceInfo key : finalPathSubresources) {
candidateList.remove(key);
@@ -1184,7 +1191,10 @@ public final class JAXRSUtils {
} else if (ResourceInfo.class.isAssignableFrom(clazz)) {
o = new ResourceInfoImpl(contextMessage);
} else if (ResourceContext.class.isAssignableFrom(clazz)) {
- o = new ResourceContextImpl(contextMessage, contextMessage.getExchange().get(OperationResourceInfo.class));
+ OperationResourceInfo operationResourceInfo = contextMessage.getExchange().get(OperationResourceInfo.class);
+ if (operationResourceInfo != null) {
+ o = new ResourceContextImpl(contextMessage, operationResourceInfo);
+ }
} else if (Request.class.isAssignableFrom(clazz)) {
o = new RequestImpl(contextMessage);
} else if (Providers.class.isAssignableFrom(clazz)) {