/* * Copyright (C) 2015 Sebastian Daschner, sebastian-daschner.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/LICENSE2.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 com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.simulation; import com.sebastian_daschner.jaxrs_analyzer.model.elements.Element; import com.sebastian_daschner.jaxrs_analyzer.model.elements.HttpResponse; import com.sebastian_daschner.jaxrs_analyzer.model.elements.JsonValue; import com.sebastian_daschner.jaxrs_analyzer.model.elements.MethodHandle; import com.sebastian_daschner.jaxrs_analyzer.model.methods.IdentifiableMethod; import com.sebastian_daschner.jaxrs_analyzer.model.methods.Method; import com.sebastian_daschner.jaxrs_analyzer.model.methods.MethodIdentifier; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.BiFunction; import java.util.stream.Collectors; import static com.sebastian_daschner.jaxrs_analyzer.model.JavaUtils.INITIALIZER_NAME; import static com.sebastian_daschner.jaxrs_analyzer.model.Types.*; import static com.sebastian_daschner.jaxrs_analyzer.model.methods.MethodIdentifier.ofNonStatic; import static com.sebastian_daschner.jaxrs_analyzer.model.methods.MethodIdentifier.ofStatic; /** * Known methods which apply logic to the result or to the return element. * * @author Sebastian Daschner */ enum KnownResponseResultMethod implements IdentifiableMethod { // non-static methods in ResponseBuilder -------------------------- RESPONSE_BUILDER_BUILD(ofNonStatic(CLASS_RESPONSE_BUILDER, "build", RESPONSE), (object, arguments) -> object), RESPONSE_BUILDER_CACHE_CONTROL(ofNonStatic(CLASS_RESPONSE_BUILDER, "cacheControl", RESPONSE_BUILDER, "Ljavax/ws/rs/core/CacheControl;"), (object, arguments) -> addHeader(object, HttpHeaders.CACHE_CONTROL)), RESPONSE_BUILDER_CONTENT_LOCATION(ofNonStatic(CLASS_RESPONSE_BUILDER, "contentLocation", RESPONSE_BUILDER, URI), (object, arguments) -> addHeader(object, HttpHeaders.CONTENT_LOCATION)), RESPONSE_BUILDER_COOKIE(ofNonStatic(CLASS_RESPONSE_BUILDER, "cookie", RESPONSE_BUILDER, "[Ljavax/ws/rs/core/NewCookie;"), (object, arguments) -> addHeader(object, HttpHeaders.SET_COOKIE)), RESPONSE_BUILDER_ENCODING(ofNonStatic(CLASS_RESPONSE_BUILDER, "encoding", RESPONSE_BUILDER, STRING), (object, arguments) -> addHeader(object, HttpHeaders.CONTENT_ENCODING)), RESPONSE_BUILDER_ENTITY(ofNonStatic(CLASS_RESPONSE_BUILDER, "entity", RESPONSE_BUILDER, OBJECT), (object, arguments) -> addEntity(object, arguments.get(0))), RESPONSE_BUILDER_ENTITY_ANNOTATION(ofNonStatic(CLASS_RESPONSE_BUILDER, "entity", RESPONSE_BUILDER, OBJECT, "[Ljava/lang/annotation/Annotation;"), (object, arguments) -> addEntity(object, arguments.get(0))), RESPONSE_BUILDER_EXPIRES(ofNonStatic(CLASS_RESPONSE_BUILDER, "expires", RESPONSE_BUILDER, DATE), (object, arguments) -> addHeader(object, HttpHeaders.EXPIRES)), RESPONSE_BUILDER_HEADER(ofNonStatic(CLASS_RESPONSE_BUILDER, "header", RESPONSE_BUILDER, STRING, OBJECT), (object, arguments) -> { arguments.get(0).getPossibleValues().stream() .map(header -> (String) header).forEach(h -> addHeader(object, h)); return object; }), RESPONSE_BUILDER_LANGUAGE_LOCALE(ofNonStatic(CLASS_RESPONSE_BUILDER, "language", RESPONSE_BUILDER, "Ljava/util/Locale;"), (object, arguments) -> addHeader(object, HttpHeaders.CONTENT_LANGUAGE)), RESPONSE_BUILDER_LANGUAGE_STRING(ofNonStatic(CLASS_RESPONSE_BUILDER, "language", RESPONSE_BUILDER, STRING), (object, arguments) -> addHeader(object, HttpHeaders.CONTENT_LANGUAGE)), RESPONSE_BUILDER_LAST_MODIFIED(ofNonStatic(CLASS_RESPONSE_BUILDER, "lastModified", RESPONSE_BUILDER, DATE), (object, arguments) -> addHeader(object, HttpHeaders.LAST_MODIFIED)), RESPONSE_BUILDER_LINK_URI(ofNonStatic(CLASS_RESPONSE_BUILDER, "link", RESPONSE_BUILDER, URI, STRING), (object, arguments) -> addHeader(object, HttpHeaders.LINK)), RESPONSE_BUILDER_LINK_STRING(ofNonStatic(CLASS_RESPONSE_BUILDER, "link", RESPONSE_BUILDER, STRING, STRING), (object, arguments) -> addHeader(object, HttpHeaders.LINK)), RESPONSE_BUILDER_LINKS(ofNonStatic(CLASS_RESPONSE_BUILDER, "links", RESPONSE_BUILDER, "[Ljavax/ws/rs/core/Link;"), (object, arguments) -> addHeader(object, HttpHeaders.LINK)), RESPONSE_BUILDER_LOCATION(ofNonStatic(CLASS_RESPONSE_BUILDER, "location", RESPONSE_BUILDER, URI), (object, arguments) -> addHeader(object, HttpHeaders.LOCATION)), RESPONSE_BUILDER_STATUS_ENUM(ofNonStatic(CLASS_RESPONSE_BUILDER, "status", RESPONSE_BUILDER, RESPONSE_STATUS), (object, arguments) -> { arguments.get(0).getPossibleValues().stream() .map(status -> ((Response.Status) status).getStatusCode()).forEach(s -> addStatus(object, s)); return object; }), RESPONSE_BUILDER_STATUS_INT(ofNonStatic(CLASS_RESPONSE_BUILDER, "status", RESPONSE_BUILDER, PRIMITIVE_INT), (object, arguments) -> { arguments.get(0).getPossibleValues().stream() .map(status -> (int) status).forEach(s -> addStatus(object, s)); return object; }), RESPONSE_BUILDER_TAG_ENTITY(ofNonStatic(CLASS_RESPONSE_BUILDER, "tag", RESPONSE_BUILDER, ENTITY_TAG), (object, arguments) -> addHeader(object, HttpHeaders.ETAG)), RESPONSE_BUILDER_TAG_STRING(ofNonStatic(CLASS_RESPONSE_BUILDER, "tag", RESPONSE_BUILDER, STRING), (object, arguments) -> addHeader(object, HttpHeaders.ETAG)), RESPONSE_BUILDER_TYPE(ofNonStatic(CLASS_RESPONSE_BUILDER, "type", RESPONSE_BUILDER, "Ljavax/ws/rs/core/MediaType;"), (object, arguments) -> { arguments.get(0).getPossibleValues().stream() .map(m -> (MediaType) m).map(m -> m.getType() + '/' + m.getSubtype()).forEach(t -> addContentType(object, t)); return object; }), RESPONSE_BUILDER_TYPE_STRING(ofNonStatic(CLASS_RESPONSE_BUILDER, "type", RESPONSE_BUILDER, STRING), (object, arguments) -> { arguments.get(0).getPossibleValues().stream() .map(t -> (String) t).forEach(t -> addContentType(object, t)); return object; }), RESPONSE_BUILDER_VARIANT(ofNonStatic(CLASS_RESPONSE_BUILDER, "variant", RESPONSE_BUILDER, VARIANT), (object, arguments) -> { addHeader(object, HttpHeaders.CONTENT_LANGUAGE); addHeader(object, HttpHeaders.CONTENT_ENCODING); return object; }), RESPONSE_BUILDER_VARIANTS_LIST(ofNonStatic(CLASS_RESPONSE_BUILDER, "variants", RESPONSE_BUILDER, LIST), (object, arguments) -> addHeader(object, HttpHeaders.VARY)), RESPONSE_BUILDER_VARIANTS_ARRAY(ofNonStatic(CLASS_RESPONSE_BUILDER, "variants", RESPONSE_BUILDER, "[Ljavax/ws/rs/core/Variant;"), (object, arguments) -> addHeader(object, HttpHeaders.VARY)), // static methods in Response -------------------------- RESPONSE_STATUS_ENUM(ofStatic(CLASS_RESPONSE, "status", RESPONSE_BUILDER, RESPONSE_STATUS), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(0).getPossibleValues().stream() .map(status -> ((Response.Status) status).getStatusCode()).forEach(s -> addStatus(object, s)); return object; }), RESPONSE_STATUS_INT(ofStatic(CLASS_RESPONSE, "status", RESPONSE_BUILDER, PRIMITIVE_INT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(0).getPossibleValues().stream() .map(status -> (int) status).forEach(s -> addStatus(object, s)); return object; }), RESPONSE_OK(ofStatic(CLASS_RESPONSE, "ok", RESPONSE_BUILDER), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.OK.getStatusCode()); }), RESPONSE_OK_ENTITY(ofStatic(CLASS_RESPONSE, "ok", RESPONSE_BUILDER, OBJECT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.OK.getStatusCode()); return addEntity(object, arguments.get(0)); }), RESPONSE_OK_VARIANT(ofStatic(CLASS_RESPONSE, "ok", RESPONSE_BUILDER, OBJECT, VARIANT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.OK.getStatusCode()); addEntity(object, arguments.get(0)); addHeader(object, HttpHeaders.CONTENT_LANGUAGE); return addHeader(object, HttpHeaders.CONTENT_ENCODING); }), RESPONSE_OK_MEDIATYPE(ofStatic(CLASS_RESPONSE, "ok", RESPONSE_BUILDER, OBJECT, "Ljavax/ws/rs/core/MediaType;"), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.OK.getStatusCode()); arguments.get(1).getPossibleValues().stream().map(m -> (MediaType) m) .map(m -> m.getType() + '/' + m.getSubtype()).forEach(t -> addContentType(object, t)); return addEntity(object, arguments.get(0)); }), RESPONSE_OK_MEDIATYPE_STRING(ofStatic(CLASS_RESPONSE, "ok", RESPONSE_BUILDER, OBJECT, STRING), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.OK.getStatusCode()); arguments.get(1).getPossibleValues().stream() .map(t -> (String) t).forEach(t -> addContentType(object, t)); return addEntity(object, arguments.get(0)); }), RESPONSE_ACCEPTED(ofStatic(CLASS_RESPONSE, "accepted", RESPONSE_BUILDER), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.ACCEPTED.getStatusCode()); }), RESPONSE_ACCEPTED_ENTITY(ofStatic(CLASS_RESPONSE, "accepted", RESPONSE_BUILDER, OBJECT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.ACCEPTED.getStatusCode()); return addEntity(object, arguments.get(0)); }), RESPONSE_CREATED(ofStatic(CLASS_RESPONSE, "created", RESPONSE_BUILDER, URI), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.CREATED.getStatusCode()); return addHeader(object, HttpHeaders.LOCATION); }), RESPONSE_NO_CONTENT(ofStatic(CLASS_RESPONSE, "noContent", RESPONSE_BUILDER), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.NO_CONTENT.getStatusCode()); }), RESPONSE_NOT_ACCEPTABLE(ofStatic(CLASS_RESPONSE, "notAcceptable", RESPONSE_BUILDER, LIST), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.NOT_ACCEPTABLE.getStatusCode()); return addHeader(object, HttpHeaders.VARY); }), RESPONSE_NOT_MODIFIED(ofStatic(CLASS_RESPONSE, "notModified", RESPONSE_BUILDER), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.NOT_MODIFIED.getStatusCode()); }), RESPONSE_NOT_MODIFIED_ENTITYTAG(ofStatic(CLASS_RESPONSE, "notModified", RESPONSE_BUILDER, ENTITY_TAG), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.NOT_MODIFIED.getStatusCode()); return addHeader(object, HttpHeaders.ETAG); }), RESPONSE_NOT_MODIFIED_ENTITYTAG_STRING(ofStatic(CLASS_RESPONSE, "notModified", RESPONSE_BUILDER, STRING), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.NOT_MODIFIED.getStatusCode()); return addHeader(object, HttpHeaders.ETAG); }), RESPONSE_SEE_OTHER(ofStatic(CLASS_RESPONSE, "seeOther", RESPONSE_BUILDER, URI), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.SEE_OTHER.getStatusCode()); return addHeader(object, HttpHeaders.LOCATION); }), RESPONSE_TEMPORARY_REDIRECT(ofStatic(CLASS_RESPONSE, "temporaryRedirect", RESPONSE_BUILDER, URI), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); addStatus(object, Response.Status.TEMPORARY_REDIRECT.getStatusCode()); return addHeader(object, HttpHeaders.LOCATION); }), RESPONSE_SERVER_ERROR(ofStatic(CLASS_RESPONSE, "serverError", RESPONSE_BUILDER), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); }), // WebApplicationExceptions -------------------------- WEB_APPLICATION_EXCEPTION_EMPTY(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); }), WEB_APPLICATION_EXCEPTION_MESSAGE(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); }), WEB_APPLICATION_EXCEPTION_RESPONSE(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, RESPONSE), (notAvailable, arguments) -> arguments.get(0)), WEB_APPLICATION_EXCEPTION_MESSAGE_RESPONSE(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING, RESPONSE), (notAvailable, arguments) -> arguments.get(1)), WEB_APPLICATION_EXCEPTION_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, PRIMITIVE_INT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(0).getPossibleValues().stream() .map(status -> (int) status).forEach(s -> addStatus(object, s)); return object; }), WEB_APPLICATION_EXCEPTION_MESSAGE_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING, PRIMITIVE_INT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(1).getPossibleValues().stream() .map(status -> (int) status).forEach(s -> addStatus(object, s)); return object; }), WEB_APPLICATION_EXCEPTION_RESPONSE_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, RESPONSE_STATUS), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(0).getPossibleValues().stream() .map(status -> ((Response.Status) status).getStatusCode()).forEach(s -> addStatus(object, s)); return object; }), WEB_APPLICATION_EXCEPTION_MESSAGE_RESPONSE_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING, RESPONSE_STATUS), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(1).getPossibleValues().stream() .map(status -> ((Response.Status) status).getStatusCode()).forEach(s -> addStatus(object, s)); return object; }), WEB_APPLICATION_EXCEPTION_CAUSE(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, THROWABLE), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); }), WEB_APPLICATION_EXCEPTION_MESSAGE_CAUSE(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING, THROWABLE), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); return addStatus(object, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); }), WEB_APPLICATION_EXCEPTION_CAUSE_RESPONSE(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, THROWABLE, RESPONSE), (notAvailable, arguments) -> arguments.get(1)), WEB_APPLICATION_EXCEPTION_MESSAGE_CAUSE_RESPONSE(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING, THROWABLE, RESPONSE), (notAvailable, arguments) -> arguments.get(2)), WEB_APPLICATION_EXCEPTION_CAUSE_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, THROWABLE, PRIMITIVE_INT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(1).getPossibleValues().stream() .map(status -> (int) status).forEach(s -> addStatus(object, s)); return object; }), WEB_APPLICATION_EXCEPTION_MESSAGE_CAUSE_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING, THROWABLE, PRIMITIVE_INT), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(2).getPossibleValues().stream() .map(status -> (int) status).forEach(s -> addStatus(object, s)); return object; }), WEB_APPLICATION_EXCEPTION_CAUSE_RESPONSE_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, THROWABLE, RESPONSE_STATUS), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(1).getPossibleValues().stream() .map(status -> ((Response.Status) status).getStatusCode()).forEach(s -> addStatus(object, s)); return object; }), WEB_APPLICATION_EXCEPTION_MESSAGE_CAUSE_RESPONSE_STATUS(ofNonStatic(CLASS_WEB_APPLICATION_EXCEPTION, INITIALIZER_NAME, PRIMITIVE_VOID, STRING, THROWABLE, RESPONSE_STATUS), (notAvailable, arguments) -> { final Element object = new Element(RESPONSE, new HttpResponse()); arguments.get(2).getPossibleValues().stream() .map(status -> ((Response.Status) status).getStatusCode()).forEach(s -> addStatus(object, s)); return object; }), // other methods -------------------------- RESOURCE_CONTEXT_INIT(ofNonStatic(CLASS_RESOURCE_CONTEXT, "getResource", OBJECT, CLASS), (object, arguments) -> new Element(arguments.get(0).getPossibleValues().stream() .filter(s -> s instanceof String).map(s -> (String) s).collect(Collectors.toSet())) ), RESOURCE_CONTEXT_GET(ofNonStatic(CLASS_RESOURCE_CONTEXT, "initResource", OBJECT, OBJECT), (object, arguments) -> new Element(arguments.get(0).getTypes())), INTEGER_VALUE_OF(ofStatic(CLASS_INTEGER, "valueOf", PRIMITIVE_INT, INTEGER), (object, arguments) -> new Element(INTEGER, arguments.get(0).getPossibleValues().toArray())), DOUBLE_VALUE_OF(ofStatic(CLASS_DOUBLE, "valueOf", PRIMITIVE_DOUBLE, DOUBLE), (object, arguments) -> new Element(INTEGER, arguments.get(0).getPossibleValues().toArray())), LONG_VALUE_OF(ofStatic(CLASS_LONG, "valueOf", PRIMITIVE_LONG, LONG), (object, arguments) -> new Element(INTEGER, arguments.get(0).getPossibleValues().toArray())), // stream related methods -------------------------- LIST_STREAM(ofNonStatic(CLASS_LIST, "stream", STREAM), (object, arguments) -> new Element(object.getTypes())), LIST_FOR_EACH(ofNonStatic(CLASS_LIST, "forEach", PRIMITIVE_VOID, CONSUMER), (object, arguments) -> { if (arguments.get(0) instanceof MethodHandle) ((Method) arguments.get(0)).invoke(null, Collections.singletonList(object)); return null; }), SET_STREAM(ofNonStatic(CLASS_SET, "stream", STREAM), (object, arguments) -> new Element(object.getTypes())), SET_FOR_EACH(ofNonStatic(CLASS_SET, "forEach", PRIMITIVE_VOID, CONSUMER), (object, arguments) -> { if (arguments.get(0) instanceof MethodHandle) ((Method) arguments.get(0)).invoke(null, Collections.singletonList(object)); return null; }), STREAM_COLLECT(ofNonStatic(CLASS_STREAM, "collect", OBJECT, SUPPLIER, BI_CONSUMER, BI_CONSUMER), (object, arguments) -> { if (arguments.get(0) instanceof MethodHandle && arguments.get(1) instanceof MethodHandle) { final Element collectionElement = ((Method) arguments.get(0)).invoke(null, Collections.emptyList()); ((Method) arguments.get(1)).invoke(null, Arrays.asList(collectionElement, object)); return collectionElement; } return new Element(); }), STREAM_FOR_EACH(ofNonStatic(CLASS_STREAM, "forEach", PRIMITIVE_VOID, CONSUMER), (object, arguments) -> { if (arguments.get(0) instanceof MethodHandle) ((Method) arguments.get(0)).invoke(null, Collections.singletonList(object)); return null; }), STREAM_MAP(ofNonStatic(CLASS_STREAM, "map", STREAM, "Ljava/util/function/Function;"), (object, arguments) -> { if (arguments.get(0) instanceof MethodHandle) { return ((MethodHandle) arguments.get(0)).invoke(null, Collections.singletonList(object)); } return new Element(); }); private final MethodIdentifier identifier; private final BiFunction<Element, List<Element>, Element> function; KnownResponseResultMethod(final MethodIdentifier identifier, final BiFunction<Element, List<Element>, Element> function) { this.identifier = identifier; this.function = function; } @Override public Element invoke(final Element object, final List<Element> arguments) { if (arguments.size() != identifier.getParameters().size()) throw new IllegalArgumentException("Method arguments do not match expected signature!"); return function.apply(object, arguments); } @Override public boolean matches(final MethodIdentifier identifier) { return this.identifier.equals(identifier); } private static Element addHeader(final Element object, final String header) { object.getPossibleValues().stream().filter(r -> r instanceof HttpResponse).map(r -> (HttpResponse) r).forEach(r -> r.getHeaders().add(header)); return object; } private static Element addEntity(final Element object, final Element argument) { object.getPossibleValues().stream().filter(r -> r instanceof HttpResponse).map(r -> (HttpResponse) r) .forEach(r -> { r.getEntityTypes().addAll(argument.getTypes()); argument.getPossibleValues().stream().filter(j -> j instanceof JsonValue).map(j -> (JsonValue) j).forEach(j -> r.getInlineEntities().add(j)); }); return object; } private static Element addStatus(final Element object, final Integer status) { object.getPossibleValues().stream().filter(r -> r instanceof HttpResponse).map(r -> (HttpResponse) r).forEach(r -> r.getStatuses().add(status)); return object; } private static Element addContentType(final Element object, final String type) { object.getPossibleValues().stream().filter(r -> r instanceof HttpResponse).map(r -> (HttpResponse) r).forEach(r -> r.getContentTypes().add(type)); return object; } }