diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index 2dd130fc634..d17f0bf94e3 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -27,6 +27,8 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; @@ -89,6 +91,29 @@ public final class IndicesClient { listener, Collections.emptySet(), headers); } + /** + * Updates the mappings on an index using the Put Mapping API + *

+ * See + * Put Mapping API on elastic.co + */ + public PutMappingResponse putMapping(PutMappingRequest putMappingRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(putMappingRequest, Request::putMapping, PutMappingResponse::fromXContent, + Collections.emptySet(), headers); + } + + /** + * Asynchronously updates the mappings on an index using the Put Mapping API + *

+ * See + * Put Mapping API on elastic.co + */ + public void putMappingAsync(PutMappingRequest putMappingRequest, ActionListener listener, + Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(putMappingRequest, Request::putMapping, PutMappingResponse::fromXContent, + listener, Collections.emptySet(), headers); + } + /** * Opens an index using the Open Index API *

diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java index cc3b0deff52..229e45498aa 100755 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java @@ -32,6 +32,7 @@ import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; @@ -178,6 +179,22 @@ public final class Request { return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); } + static Request putMapping(PutMappingRequest putMappingRequest) throws IOException { + // The concreteIndex is an internal concept, not applicable to requests made over the REST API. + if (putMappingRequest.getConcreteIndex() != null) { + throw new IllegalArgumentException("concreteIndex cannot be set on PutMapping requests made over the REST API"); + } + + String endpoint = endpoint(putMappingRequest.indices(), "_mapping", putMappingRequest.type()); + + Params parameters = Params.builder(); + parameters.withTimeout(putMappingRequest.timeout()); + parameters.withMasterTimeout(putMappingRequest.masterNodeTimeout()); + + HttpEntity entity = createEntity(putMappingRequest, REQUEST_BODY_CONTENT_TYPE); + return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); + } + static Request info() { return new Request(HttpGet.METHOD_NAME, "/", Collections.emptyMap(), null); } @@ -454,6 +471,10 @@ public final class Request { return endpoint(String.join(",", indices), String.join(",", types), endpoint); } + static String endpoint(String[] indices, String endpoint, String type) { + return endpoint(String.join(",", indices), endpoint, type); + } + /** * Utility method to build request's endpoint. */ diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java index 5f8702807fb..2f81479f93a 100755 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -27,6 +27,8 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.support.IndicesOptions; @@ -108,6 +110,35 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { } } + @SuppressWarnings("unchecked") + public void testPutMapping() throws IOException { + { + // Add mappings to index + String indexName = "mapping_index"; + createIndex(indexName); + + PutMappingRequest putMappingRequest = new PutMappingRequest(indexName); + putMappingRequest.type("type_name"); + XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); + mappingBuilder.startObject().startObject("properties").startObject("field"); + mappingBuilder.field("type", "text"); + mappingBuilder.endObject().endObject().endObject(); + putMappingRequest.source(mappingBuilder); + + PutMappingResponse putMappingResponse = + execute(putMappingRequest, highLevelClient().indices()::putMapping, highLevelClient().indices()::putMappingAsync); + assertTrue(putMappingResponse.isAcknowledged()); + + Map indexMetaData = getIndexMetadata(indexName); + Map mappingsData = (Map) indexMetaData.get("mappings"); + Map typeData = (Map) mappingsData.get("type_name"); + Map properties = (Map) typeData.get("properties"); + Map field = (Map) properties.get("field"); + + assertEquals("text", field.get("type")); + } + } + public void testDeleteIndex() throws IOException { { // Delete index if exists diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java index 49667a3dee2..0ddaf1de1ca 100755 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java @@ -28,6 +28,7 @@ import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkShardRequest; @@ -317,6 +318,39 @@ public class RequestTests extends ESTestCase { assertToXContentBody(createIndexRequest, request.getEntity()); } + public void testPutMapping() throws IOException { + PutMappingRequest putMappingRequest = new PutMappingRequest(); + + int numIndices = randomIntBetween(0, 5); + String[] indices = new String[numIndices]; + for (int i = 0; i < numIndices; i++) { + indices[i] = "index-" + randomAlphaOfLengthBetween(2, 5); + } + putMappingRequest.indices(indices); + + String type = randomAlphaOfLengthBetween(3, 10); + putMappingRequest.type(type); + + Map expectedParams = new HashMap<>(); + + setRandomTimeout(putMappingRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + setRandomMasterTimeout(putMappingRequest, expectedParams); + + Request request = Request.putMapping(putMappingRequest); + StringJoiner endpoint = new StringJoiner("/", "/", ""); + String index = String.join(",", indices); + if (Strings.hasLength(index)) { + endpoint.add(index); + } + endpoint.add("_mapping"); + endpoint.add(type); + assertEquals(endpoint.toString(), request.getEndpoint()); + + assertEquals(expectedParams, request.getParameters()); + assertEquals("PUT", request.getMethod()); + assertToXContentBody(putMappingRequest, request.getEntity()); + } + public void testDeleteIndex() { String[] indices = randomIndicesNames(0, 5); DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indices); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index bc3b1698f96..23029c7c6b0 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -28,6 +28,8 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.support.ActiveShardCount; @@ -157,15 +159,15 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase // tag::create-index-request-mappings request.mapping("tweet", // <1> - " {\n" + - " \"tweet\": {\n" + - " \"properties\": {\n" + - " \"message\": {\n" + - " \"type\": \"text\"\n" + - " }\n" + + "{\n" + + " \"tweet\": {\n" + + " \"properties\": {\n" + + " \"message\": {\n" + + " \"type\": \"text\"\n" + " }\n" + " }\n" + - " }", // <2> + " }\n" + + "}", // <2> XContentType.JSON); // end::create-index-request-mappings @@ -228,6 +230,86 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase } } + public void testPutMapping() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter")); + assertTrue(createIndexResponse.isAcknowledged()); + } + + { + // tag::put-mapping-request + PutMappingRequest request = new PutMappingRequest("twitter"); // <1> + request.type("tweet"); // <2> + // end::put-mapping-request + + // tag::put-mapping-request-source + request.source( + "{\n" + + " \"tweet\": {\n" + + " \"properties\": {\n" + + " \"message\": {\n" + + " \"type\": \"text\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}", // <1> + XContentType.JSON); + // end::put-mapping-request-source + + // tag::put-mapping-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::put-mapping-request-timeout + // tag::put-mapping-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::put-mapping-request-masterTimeout + + // tag::put-mapping-execute + PutMappingResponse putMappingResponse = client.indices().putMapping(request); + // end::put-mapping-execute + + // tag::put-mapping-response + boolean acknowledged = putMappingResponse.isAcknowledged(); // <1> + // end::put-mapping-response + assertTrue(acknowledged); + } + } + + public void testPutMappingAsync() throws Exception { + final RestHighLevelClient client = highLevelClient(); + + { + CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter")); + assertTrue(createIndexResponse.isAcknowledged()); + } + + { + PutMappingRequest request = new PutMappingRequest("twitter").type("tweet"); + // tag::put-mapping-execute-async + client.indices().putMappingAsync(request, new ActionListener() { + @Override + public void onResponse(PutMappingResponse putMappingResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }); + // end::put-mapping-execute-async + + assertBusy(() -> { + // TODO Use Indices Exist API instead once it exists + Response response = client.getLowLevelClient().performRequest("HEAD", "twitter"); + assertTrue(RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode()); + }); + } + } + public void testOpenIndex() throws IOException { RestHighLevelClient client = highLevelClient(); diff --git a/docs/java-rest/high-level/apis/index.asciidoc b/docs/java-rest/high-level/apis/index.asciidoc index f6da998a847..f7367b6e8c2 100644 --- a/docs/java-rest/high-level/apis/index.asciidoc +++ b/docs/java-rest/high-level/apis/index.asciidoc @@ -6,6 +6,8 @@ include::open_index.asciidoc[] include::close_index.asciidoc[] +include::putmapping.asciidoc[] + include::_index.asciidoc[] include::get.asciidoc[] diff --git a/docs/java-rest/high-level/apis/putmapping.asciidoc b/docs/java-rest/high-level/apis/putmapping.asciidoc new file mode 100644 index 00000000000..57b8ec8964a --- /dev/null +++ b/docs/java-rest/high-level/apis/putmapping.asciidoc @@ -0,0 +1,71 @@ +[[java-rest-high-put-mapping]] +=== Put Mapping API + +[[java-rest-high-put-mapping-request]] +==== Put Mapping Request + +A `PutMappingRequest` requires an `index` argument, and a type: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request] +-------------------------------------------------- +<1> The index to add the mapping to +<2> The type to create (or update) + +==== Mapping source +A description of the fields to create on the mapping; if not defined, the mapping will default to empty. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request-source] +-------------------------------------------------- +<1> The mapping source + +==== Optional arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request-timeout] +-------------------------------------------------- +<1> Timeout to wait for the all the nodes to acknowledge the index creation as a `TimeValue` +<2> Timeout to wait for the all the nodes to acknowledge the index creation as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request-masterTimeout] +-------------------------------------------------- +<1> Timeout to connect to the master node as a `TimeValue` +<2> Timeout to connect to the master node as a `String` + +[[java-rest-high-put-mapping-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-execute] +-------------------------------------------------- + +[[java-rest-high-put-mapping-async]] +==== Asynchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-execute-async] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of failure. The raised exception is provided as an argument + +[[java-rest-high-put-mapping-response]] +==== Put Mapping Response + +The returned `PutMappingResponse` allows to retrieve information about the executed + operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-response] +-------------------------------------------------- +<1> Indicates whether all of the nodes have acknowledged the request diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index fa71b62d64e..aede4789f4d 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -8,6 +8,7 @@ Indices APIs:: * <> * <> * <> +* <> Single document APIs:: * <> diff --git a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc index 2e4b9a11011..be18689bfdd 100644 --- a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc +++ b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc @@ -224,8 +224,40 @@ Time values can also be specified via abbreviations supported by < + } + } + } + ] + } + } + } +} +-------------------------------------------------- +// CONSOLE + +<1> Supports expressive date <> + +====== Time Zone Date-times are stored in Elasticsearch in UTC. By default, all bucketing and rounding is also done in UTC. The `time_zone` parameter can be used to indicate diff --git a/docs/reference/query-dsl/query-string-syntax.asciidoc b/docs/reference/query-dsl/query-string-syntax.asciidoc index 8a7b394b2e8..c73543c99a1 100644 --- a/docs/reference/query-dsl/query-string-syntax.asciidoc +++ b/docs/reference/query-dsl/query-string-syntax.asciidoc @@ -56,7 +56,7 @@ match the query string `"a* b* c*"`. [WARNING] ======= Pure wildcards `\*` are rewritten to <> queries for efficiency. -As a consequence, the wildcard `"field:*"` would match documents with an emtpy value +As a consequence, the wildcard `"field:*"` would match documents with an empty value like the following: ``` { diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java index eef9d7af8dd..79319369489 100644 --- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java +++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java @@ -20,6 +20,7 @@ package org.elasticsearch.script.mustache; import com.github.mustachejava.reflect.ReflectionObjectHandler; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.util.iterable.Iterables; import java.lang.reflect.Array; @@ -154,4 +155,9 @@ final class CustomReflectionObjectHandler extends ReflectionObjectHandler { } } + @Override + public String stringify(Object object) { + CollectionUtils.ensureNoSelfReferences(object); + return super.stringify(object); + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java index 89f358d17e0..abba62de39c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java @@ -20,7 +20,7 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Cast; -import org.elasticsearch.painless.Definition.Type; +import org.elasticsearch.painless.Definition.def; import java.util.Objects; @@ -30,453 +30,448 @@ import java.util.Objects; */ public final class AnalyzerCaster { - private Definition definition; - - public AnalyzerCaster(Definition definition) { - this.definition = definition; - } - - public Cast getLegalCast(Location location, Type actual, Type expected, boolean explicit, boolean internal) { + public static Cast getLegalCast(Location location, Class actual, Class expected, boolean explicit, boolean internal) { Objects.requireNonNull(actual); Objects.requireNonNull(expected); - if (actual.equals(expected)) { + if (actual == expected) { return null; } - if (actual.dynamic) { - if (expected.clazz == boolean.class) { - return Cast.unboxTo(definition.DefType, definition.BooleanType, explicit, definition.booleanType); - } else if (expected.clazz == byte.class) { - return Cast.unboxTo(definition.DefType, definition.ByteType, explicit, definition.byteType); - } else if (expected.clazz == short.class) { - return Cast.unboxTo(definition.DefType, definition.ShortType, explicit, definition.shortType); - } else if (expected.clazz == char.class) { - return Cast.unboxTo(definition.DefType, definition.CharacterType, explicit, definition.charType); - } else if (expected.clazz == int.class) { - return Cast.unboxTo(definition.DefType, definition.IntegerType, explicit, definition.intType); - } else if (expected.clazz == long.class) { - return Cast.unboxTo(definition.DefType, definition.LongType, explicit, definition.longType); - } else if (expected.clazz == float.class) { - return Cast.unboxTo(definition.DefType, definition.FloatType, explicit, definition.floatType); - } else if (expected.clazz == double.class) { - return Cast.unboxTo(definition.DefType, definition.DoubleType, explicit, definition.doubleType); + if (actual == def.class) { + if (expected == boolean.class) { + return Cast.unboxTo(def.class, Boolean.class, explicit, boolean.class); + } else if (expected == byte.class) { + return Cast.unboxTo(def.class, Byte.class, explicit, byte.class); + } else if (expected == short.class) { + return Cast.unboxTo(def.class, Short.class, explicit, short.class); + } else if (expected == char.class) { + return Cast.unboxTo(def.class, Character.class, explicit, char.class); + } else if (expected == int.class) { + return Cast.unboxTo(def.class, Integer.class, explicit, int.class); + } else if (expected == long.class) { + return Cast.unboxTo(def.class, Long.class, explicit, long.class); + } else if (expected == float.class) { + return Cast.unboxTo(def.class, Float.class, explicit, float.class); + } else if (expected == double.class) { + return Cast.unboxTo(def.class, Double.class, explicit, double.class); } - } else if (actual.clazz == Object.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.ByteType, true, definition.byteType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.ShortType, true, definition.shortType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.CharacterType, true, definition.charType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.IntegerType, true, definition.intType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.LongType, true, definition.longType); - } else if (expected.clazz == float.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.FloatType, true, definition.floatType); - } else if (expected.clazz == double.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.DoubleType, true, definition.doubleType); + } else if (actual == Object.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxTo(Object.class, Byte.class, true, byte.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxTo(Object.class, Short.class, true, short.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxTo(Object.class, Character.class, true, char.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxTo(Object.class, Integer.class, true, int.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxTo(Object.class, Long.class, true, long.class); + } else if (expected == float.class && explicit && internal) { + return Cast.unboxTo(Object.class, Float.class, true, float.class); + } else if (expected == double.class && explicit && internal) { + return Cast.unboxTo(Object.class, Double.class, true, double.class); } - } else if (actual.clazz == Number.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.ByteType, true, definition.byteType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.ShortType, true, definition.shortType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.CharacterType, true, definition.charType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.IntegerType, true, definition.intType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.LongType, true, definition.longType); - } else if (expected.clazz == float.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.FloatType, true, definition.floatType); - } else if (expected.clazz == double.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.DoubleType, true, definition.doubleType); + } else if (actual == Number.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxTo(Number.class, Byte.class, true, byte.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxTo(Number.class, Short.class, true, short.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxTo(Number.class, Character.class, true, char.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxTo(Number.class, Integer.class, true, int.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxTo(Number.class, Long.class, true, long.class); + } else if (expected == float.class && explicit && internal) { + return Cast.unboxTo(Number.class, Float.class, true, float.class); + } else if (expected == double.class && explicit && internal) { + return Cast.unboxTo(Number.class, Double.class, true, double.class); } - } else if (actual.clazz == String.class) { - if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.StringType, definition.charType, true); + } else if (actual == String.class) { + if (expected == char.class && explicit) { + return Cast.standard(String.class, char.class, true); } - } else if (actual.clazz == boolean.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.BooleanType, definition.DefType, explicit, definition.booleanType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.BooleanType, definition.ObjectType, explicit, definition.booleanType); - } else if (expected.clazz == Boolean.class && internal) { - return Cast.boxTo(definition.booleanType, definition.booleanType, explicit, definition.booleanType); + } else if (actual == boolean.class) { + if (expected == def.class) { + return Cast.boxFrom(Boolean.class, def.class, explicit, boolean.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Boolean.class, Object.class, explicit, boolean.class); + } else if (expected == Boolean.class && internal) { + return Cast.boxTo(boolean.class, boolean.class, explicit, boolean.class); } - } else if (actual.clazz == byte.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.ByteType, definition.DefType, explicit, definition.byteType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.ByteType, definition.ObjectType, explicit, definition.byteType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.ByteType, definition.NumberType, explicit, definition.byteType); - } else if (expected.clazz == short.class) { - return Cast.standard(definition.byteType, definition.shortType, explicit); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.byteType, definition.charType, true); - } else if (expected.clazz == int.class) { - return Cast.standard(definition.byteType, definition.intType, explicit); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.byteType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.byteType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.byteType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && internal) { - return Cast.boxTo(definition.byteType, definition.byteType, explicit, definition.byteType); - } else if (expected.clazz == Short.class && internal) { - return Cast.boxTo(definition.byteType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.byteType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.byteType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.byteType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.byteType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.byteType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == byte.class) { + if (expected == def.class) { + return Cast.boxFrom(Byte.class, def.class, explicit, byte.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Byte.class, Object.class, explicit, byte.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Byte.class, Number.class, explicit, byte.class); + } else if (expected == short.class) { + return Cast.standard(byte.class, short.class, explicit); + } else if (expected == char.class && explicit) { + return Cast.standard(byte.class, char.class, true); + } else if (expected == int.class) { + return Cast.standard(byte.class, int.class, explicit); + } else if (expected == long.class) { + return Cast.standard(byte.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(byte.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(byte.class, double.class, explicit); + } else if (expected == Byte.class && internal) { + return Cast.boxTo(byte.class, byte.class, explicit, byte.class); + } else if (expected == Short.class && internal) { + return Cast.boxTo(byte.class, short.class, explicit, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(byte.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(byte.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(byte.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(byte.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(byte.class, double.class, explicit, double.class); } - } else if (actual.clazz == short.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.ShortType, definition.DefType, explicit, definition.shortType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.ShortType, definition.ObjectType, explicit, definition.shortType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.ShortType, definition.NumberType, explicit, definition.shortType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.shortType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.shortType, definition.charType, true); - } else if (expected.clazz == int.class) { - return Cast.standard(definition.shortType, definition.intType, explicit); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.shortType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.shortType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.shortType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.shortType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && internal) { - return Cast.boxTo(definition.shortType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.shortType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.shortType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.shortType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.shortType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.shortType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == short.class) { + if (expected == def.class) { + return Cast.boxFrom(Short.class, def.class, explicit, short.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Short.class, Object.class, explicit, short.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Short.class, Number.class, explicit, short.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(short.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(short.class, char.class, true); + } else if (expected == int.class) { + return Cast.standard(short.class, int.class, explicit); + } else if (expected == long.class) { + return Cast.standard(short.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(short.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(short.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(short.class, byte.class, true, byte.class); + } else if (expected == Short.class && internal) { + return Cast.boxTo(short.class, short.class, explicit, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(short.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(short.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(short.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(short.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(short.class, double.class, explicit, double.class); } - } else if (actual.clazz == char.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.CharacterType, definition.DefType, explicit, definition.charType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.CharacterType, definition.ObjectType, explicit, definition.charType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.CharacterType, definition.NumberType, explicit, definition.charType); - } else if (expected.clazz == String.class) { - return Cast.standard(definition.charType, definition.StringType, explicit); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.charType, definition.byteType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.charType, definition.shortType, true); - } else if (expected.clazz == int.class) { - return Cast.standard(definition.charType, definition.intType, explicit); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.charType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.charType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.charType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.charType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && internal) { - return Cast.boxTo(definition.charType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == Character.class && internal) { - return Cast.boxTo(definition.charType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.charType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.charType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.charType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.charType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == char.class) { + if (expected == def.class) { + return Cast.boxFrom(Character.class, def.class, explicit, char.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Character.class, Object.class, explicit, char.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Character.class, Number.class, explicit, char.class); + } else if (expected == String.class) { + return Cast.standard(char.class, String.class, explicit); + } else if (expected == byte.class && explicit) { + return Cast.standard(char.class, byte.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(char.class, short.class, true); + } else if (expected == int.class) { + return Cast.standard(char.class, int.class, explicit); + } else if (expected == long.class) { + return Cast.standard(char.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(char.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(char.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(char.class, byte.class, true, byte.class); + } else if (expected == Short.class && internal) { + return Cast.boxTo(char.class, short.class, explicit, short.class); + } else if (expected == Character.class && internal) { + return Cast.boxTo(char.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(char.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(char.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(char.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(char.class, double.class, explicit, double.class); } - } else if (actual.clazz == int.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.IntegerType, definition.DefType, explicit, definition.intType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.IntegerType, definition.ObjectType, explicit, definition.intType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.IntegerType, definition.NumberType, explicit, definition.intType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.intType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.intType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.intType, definition.shortType, true); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.intType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.intType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.intType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.intType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.intType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.intType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.intType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.intType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.intType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.intType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == int.class) { + if (expected == def.class) { + return Cast.boxFrom(Integer.class, def.class, explicit, int.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Integer.class, Object.class, explicit, int.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Integer.class, Number.class, explicit, int.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(int.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(int.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(int.class, short.class, true); + } else if (expected == long.class) { + return Cast.standard(int.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(int.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(int.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(int.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(int.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(int.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(int.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(int.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(int.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(int.class, double.class, explicit, double.class); } - } else if (actual.clazz == long.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.LongType, definition.DefType, explicit, definition.longType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.LongType, definition.ObjectType, explicit, definition.longType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.LongType, definition.NumberType, explicit, definition.longType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.longType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.longType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.longType, definition.shortType, true); - } else if (expected.clazz == int.class && explicit) { - return Cast.standard(definition.longType, definition.intType, true); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.longType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.longType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.intType, true, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.longType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.longType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.longType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == long.class) { + if (expected == def.class) { + return Cast.boxFrom(Long.class, def.class, explicit, long.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Long.class, Object.class, explicit, long.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Long.class, Number.class, explicit, long.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(long.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(long.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(long.class, short.class, true); + } else if (expected == int.class && explicit) { + return Cast.standard(long.class, int.class, true); + } else if (expected == float.class) { + return Cast.standard(long.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(long.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(long.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(long.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(long.class, char.class, true, char.class); + } else if (expected == Integer.class && explicit && internal) { + return Cast.boxTo(long.class, int.class, true, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(long.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(long.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(long.class, double.class, explicit, double.class); } - } else if (actual.clazz == float.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.FloatType, definition.DefType, explicit, definition.floatType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.FloatType, definition.ObjectType, explicit, definition.floatType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.FloatType, definition.NumberType, explicit, definition.floatType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.floatType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.floatType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.floatType, definition.shortType, true); - } else if (expected.clazz == int.class && explicit) { - return Cast.standard(definition.floatType, definition.intType, true); - } else if (expected.clazz == long.class && explicit) { - return Cast.standard(definition.floatType, definition.longType, true); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.floatType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.intType, true, definition.intType); - } else if (expected.clazz == Long.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.longType, true, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.floatType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.floatType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == float.class) { + if (expected == def.class) { + return Cast.boxFrom(Float.class, def.class, explicit, float.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Float.class, Object.class, explicit, float.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Float.class, Number.class, explicit, float.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(float.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(float.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(float.class, short.class, true); + } else if (expected == int.class && explicit) { + return Cast.standard(float.class, int.class, true); + } else if (expected == long.class && explicit) { + return Cast.standard(float.class, long.class, true); + } else if (expected == double.class) { + return Cast.standard(float.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(float.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(float.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(float.class, char.class, true, char.class); + } else if (expected == Integer.class && explicit && internal) { + return Cast.boxTo(float.class, int.class, true, int.class); + } else if (expected == Long.class && explicit && internal) { + return Cast.boxTo(float.class, long.class, true, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(float.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(float.class, double.class, explicit, double.class); } - } else if (actual.clazz == double.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.DoubleType, definition.DefType, explicit, definition.doubleType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.DoubleType, definition.ObjectType, explicit, definition.doubleType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.DoubleType, definition.NumberType, explicit, definition.doubleType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.doubleType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.doubleType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.doubleType, definition.shortType, true); - } else if (expected.clazz == int.class && explicit) { - return Cast.standard(definition.doubleType, definition.intType, true); - } else if (expected.clazz == long.class && explicit) { - return Cast.standard(definition.doubleType, definition.longType, true); - } else if (expected.clazz == float.class && explicit) { - return Cast.standard(definition.doubleType, definition.floatType, true); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.intType, true, definition.intType); - } else if (expected.clazz == Long.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.longType, true, definition.longType); - } else if (expected.clazz == Float.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.floatType, true, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.doubleType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == double.class) { + if (expected == def.class) { + return Cast.boxFrom(Double.class, def.class, explicit, double.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Double.class, Object.class, explicit, double.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Double.class, Number.class, explicit, double.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(double.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(double.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(double.class, short.class, true); + } else if (expected == int.class && explicit) { + return Cast.standard(double.class, int.class, true); + } else if (expected == long.class && explicit) { + return Cast.standard(double.class, long.class, true); + } else if (expected == float.class && explicit) { + return Cast.standard(double.class, float.class, true); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(double.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(double.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(double.class, char.class, true, char.class); + } else if (expected == Integer.class && explicit && internal) { + return Cast.boxTo(double.class, int.class, true, int.class); + } else if (expected == Long.class && explicit && internal) { + return Cast.boxTo(double.class, long.class, true, long.class); + } else if (expected == Float.class && explicit && internal) { + return Cast.boxTo(double.class, float.class, true, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(double.class, double.class, explicit, double.class); } - } else if (actual.clazz == Boolean.class) { - if (expected.clazz == boolean.class && internal) { - return Cast.unboxFrom(definition.booleanType, definition.booleanType, explicit, definition.booleanType); + } else if (actual == Boolean.class) { + if (expected == boolean.class && internal) { + return Cast.unboxFrom(boolean.class, boolean.class, explicit, boolean.class); } - } else if (actual.clazz == Byte.class) { - if (expected.clazz == byte.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.byteType, explicit, definition.byteType); - } else if (expected.clazz == short.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.shortType, explicit, definition.byteType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.byteType, definition.charType, true, definition.byteType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.intType, explicit, definition.byteType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.longType, explicit, definition.byteType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.floatType, explicit, definition.byteType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.doubleType, explicit, definition.byteType); + } else if (actual == Byte.class) { + if (expected == byte.class && internal) { + return Cast.unboxFrom(byte.class, byte.class, explicit, byte.class); + } else if (expected == short.class && internal) { + return Cast.unboxFrom(byte.class, short.class, explicit, byte.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(byte.class, char.class, true, byte.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(byte.class, int.class, explicit, byte.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(byte.class, long.class, explicit, byte.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(byte.class, float.class, explicit, byte.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(byte.class, double.class, explicit, byte.class); } - } else if (actual.clazz == Short.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.shortType, definition.byteType, true, definition.shortType); - } else if (expected.clazz == short.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.shortType, definition.charType, true, definition.shortType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.intType, explicit, definition.shortType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.longType, explicit, definition.shortType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.floatType, explicit, definition.shortType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.doubleType, explicit, definition.shortType); + } else if (actual == Short.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(short.class, byte.class, true, short.class); + } else if (expected == short.class && internal) { + return Cast.unboxFrom(short.class, short.class, explicit, short.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(short.class, char.class, true, short.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(short.class, int.class, explicit, short.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(short.class, long.class, explicit, short.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(short.class, float.class, explicit, short.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(short.class, double.class, explicit, short.class); } - } else if (actual.clazz == Character.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.charType, definition.byteType, true, definition.charType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.charType, definition.shortType, true, definition.charType); - } else if (expected.clazz == char.class && internal) { - return Cast.unboxFrom(definition.charType, definition.charType, explicit, definition.charType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.charType, definition.intType, explicit, definition.charType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.charType, definition.longType, explicit, definition.charType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.charType, definition.floatType, explicit, definition.charType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.charType, definition.doubleType, explicit, definition.charType); + } else if (actual == Character.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(char.class, byte.class, true, char.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(char.class, short.class, true, char.class); + } else if (expected == char.class && internal) { + return Cast.unboxFrom(char.class, char.class, explicit, char.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(char.class, int.class, explicit, char.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(char.class, long.class, explicit, char.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(char.class, float.class, explicit, char.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(char.class, double.class, explicit, char.class); } - } else if (actual.clazz == Integer.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.intType, definition.byteType, true, definition.intType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.intType, definition.shortType, true, definition.intType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.intType, definition.charType, true, definition.intType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.intType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.intType, definition.longType, explicit, definition.intType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.intType, definition.floatType, explicit, definition.intType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.intType, definition.doubleType, explicit, definition.intType); + } else if (actual == Integer.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(int.class, byte.class, true, int.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(int.class, short.class, true, int.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(int.class, char.class, true, int.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(int.class, int.class, explicit, int.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(int.class, long.class, explicit, int.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(int.class, float.class, explicit, int.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(int.class, double.class, explicit, int.class); } - } else if (actual.clazz == Long.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.byteType, true, definition.longType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.shortType, true, definition.longType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.charType, true, definition.longType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.intType, true, definition.longType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.longType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.longType, definition.floatType, explicit, definition.longType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.longType, definition.doubleType, explicit, definition.longType); + } else if (actual == Long.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(long.class, byte.class, true, long.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(long.class, short.class, true, long.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(long.class, char.class, true, long.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxFrom(long.class, int.class, true, long.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(long.class, long.class, explicit, long.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(long.class, float.class, explicit, long.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(long.class, double.class, explicit, long.class); } - } else if (actual.clazz == Float.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.byteType, true, definition.floatType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.shortType, true, definition.floatType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.charType, true, definition.floatType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.intType, true, definition.floatType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.longType, true, definition.floatType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.floatType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.floatType, definition.doubleType, explicit, definition.floatType); + } else if (actual == Float.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(float.class, byte.class, true, float.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(float.class, short.class, true, float.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(float.class, char.class, true, float.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxFrom(float.class, int.class, true, float.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxFrom(float.class, long.class, true, float.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(float.class, float.class, explicit, float.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(float.class, double.class, explicit, float.class); } - } else if (actual.clazz == Double.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.byteType, true, definition.doubleType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.shortType, true, definition.doubleType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.charType, true, definition.doubleType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.intType, true, definition.doubleType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.longType, true, definition.doubleType); - } else if (expected.clazz == float.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.floatType, true, definition.doubleType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.doubleType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == Double.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(double.class, byte.class, true, double.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(double.class, short.class, true, double.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(double.class, char.class, true, double.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxFrom(double.class, int.class, true, double.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxFrom(double.class, long.class, true, double.class); + } else if (expected == float.class && explicit && internal) { + return Cast.unboxFrom(double.class, float.class, true, double.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(double.class, double.class, explicit, double.class); } } - if ( actual.dynamic || - (actual.clazz != void.class && expected.dynamic) || - expected.clazz.isAssignableFrom(actual.clazz) || - (actual.clazz.isAssignableFrom(expected.clazz) && explicit)) { + if ( actual == def.class || + (actual != void.class && expected == def.class) || + expected.isAssignableFrom(actual) || + (actual.isAssignableFrom(expected) && explicit)) { return Cast.standard(actual, expected, explicit); } else { - throw location.createError(new ClassCastException("Cannot cast from [" + actual.name + "] to [" + expected.name + "].")); + throw location.createError(new ClassCastException( + "Cannot cast from [" + Definition.ClassToName(actual) + "] to [" + Definition.ClassToName(expected) + "].")); } } - public Object constCast(Location location, final Object constant, final Cast cast) { - Class fsort = cast.from.clazz; - Class tsort = cast.to.clazz; + public static Object constCast(Location location, Object constant, Cast cast) { + Class fsort = cast.from; + Class tsort = cast.to; if (fsort == tsort) { return constant; @@ -485,7 +480,7 @@ public final class AnalyzerCaster { } else if (fsort == char.class && tsort == String.class) { return Utility.charToString((char)constant); } else if (fsort.isPrimitive() && fsort != boolean.class && tsort.isPrimitive() && tsort != boolean.class) { - final Number number; + Number number; if (fsort == char.class) { number = (int)(char)constant; @@ -502,232 +497,209 @@ public final class AnalyzerCaster { else if (tsort == double.class) return number.doubleValue(); else { throw location.createError(new IllegalStateException("Cannot cast from " + - "[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "].")); + "[" + cast.from.getCanonicalName() + "] to [" + cast.to.getCanonicalName() + "].")); } } else { throw location.createError(new IllegalStateException("Cannot cast from " + - "[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "].")); + "[" + cast.from.getCanonicalName() + "] to [" + cast.to.getCanonicalName() + "].")); } } - public Type promoteNumeric(Type from, boolean decimal) { - Class sort = from.clazz; - - if (from.dynamic) { - return definition.DefType; - } else if ((sort == double.class) && decimal) { - return definition.doubleType; - } else if ((sort == float.class) && decimal) { - return definition.floatType; - } else if (sort == long.class) { - return definition.longType; - } else if (sort == int.class || sort == char.class || sort == short.class || sort == byte.class) { - return definition.intType; + public static Class promoteNumeric(Class from, boolean decimal) { + if (from == def.class || from == double.class && decimal || from == float.class && decimal || from == long.class) { + return from; + } else if (from == int.class || from == char.class || from == short.class || from == byte.class) { + return int.class; } return null; } - public Type promoteNumeric(Type from0, Type from1, boolean decimal) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + public static Class promoteNumeric(Class from0, Class from1, boolean decimal) { + if (from0 == def.class || from1 == def.class) { + return def.class; } if (decimal) { - if (sort0 == double.class || sort1 == double.class) { - return definition.doubleType; - } else if (sort0 == float.class || sort1 == float.class) { - return definition.floatType; + if (from0 == double.class || from1 == double.class) { + return double.class; + } else if (from0 == float.class || from1 == float.class) { + return float.class; } } - if (sort0 == long.class || sort1 == long.class) { - return definition.longType; - } else if (sort0 == int.class || sort1 == int.class || - sort0 == char.class || sort1 == char.class || - sort0 == short.class || sort1 == short.class || - sort0 == byte.class || sort1 == byte.class) { - return definition.intType; + if (from0 == long.class || from1 == long.class) { + return long.class; + } else if (from0 == int.class || from1 == int.class || + from0 == char.class || from1 == char.class || + from0 == short.class || from1 == short.class || + from0 == byte.class || from1 == byte.class) { + return int.class; } return null; } - public Type promoteAdd(Type from0, Type from1) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (sort0 == String.class || sort1 == String.class) { - return definition.StringType; + public static Class promoteAdd(Class from0, Class from1) { + if (from0 == String.class || from1 == String.class) { + return String.class; } return promoteNumeric(from0, from1, true); } - public Type promoteXor(Type from0, Type from1) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + public static Class promoteXor(Class from0, Class from1) { + if (from0 == def.class || from1 == def.class) { + return def.class; } - if (sort0 == boolean.class || sort1 == boolean.class) { - return definition.booleanType; + if (from0 == boolean.class || from1 == boolean.class) { + return boolean.class; } return promoteNumeric(from0, from1, false); } - public Type promoteEquality(Type from0, Type from1) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + public static Class promoteEquality(Class from0, Class from1) { + if (from0 == def.class || from1 == def.class) { + return def.class; } - if (sort0.isPrimitive() && sort1.isPrimitive()) { - if (sort0 == boolean.class && sort1 == boolean.class) { - return definition.booleanType; + if (from0.isPrimitive() && from1.isPrimitive()) { + if (from0 == boolean.class && from1 == boolean.class) { + return boolean.class; } return promoteNumeric(from0, from1, true); } - return definition.ObjectType; + return Object.class; } - public Type promoteConditional(Type from0, Type from1, Object const0, Object const1) { - if (from0.equals(from1)) { + public static Class promoteConditional(Class from0, Class from1, Object const0, Object const1) { + if (from0 == from1) { return from0; } - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + if (from0 == def.class || from1 == def.class) { + return def.class; } - if (sort0.isPrimitive() && sort1.isPrimitive()) { - if (sort0 == boolean.class && sort1 == boolean.class) { - return definition.booleanType; + if (from0.isPrimitive() && from1.isPrimitive()) { + if (from0 == boolean.class && from1 == boolean.class) { + return boolean.class; } - if (sort0 == double.class || sort1 == double.class) { - return definition.doubleType; - } else if (sort0 == float.class || sort1 == float.class) { - return definition.floatType; - } else if (sort0 == long.class || sort1 == long.class) { - return definition.longType; + if (from0 == double.class || from1 == double.class) { + return double.class; + } else if (from0 == float.class || from1 == float.class) { + return float.class; + } else if (from0 == long.class || from1 == long.class) { + return long.class; } else { - if (sort0 == byte.class) { - if (sort1 == byte.class) { - return definition.byteType; - } else if (sort1 == short.class) { + if (from0 == byte.class) { + if (from1 == byte.class) { + return byte.class; + } else if (from1 == short.class) { if (const1 != null) { final short constant = (short)const1; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.shortType; - } else if (sort1 == char.class) { - return definition.intType; - } else if (sort1 == int.class) { + return short.class; + } else if (from1 == char.class) { + return int.class; + } else if (from1 == int.class) { if (const1 != null) { final int constant = (int)const1; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; + return int.class; } - } else if (sort0 == short.class) { - if (sort1 == byte.class) { + } else if (from0 == short.class) { + if (from1 == byte.class) { if (const0 != null) { final short constant = (short)const0; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.shortType; - } else if (sort1 == short.class) { - return definition.shortType; - } else if (sort1 == char.class) { - return definition.intType; - } else if (sort1 == int.class) { + return short.class; + } else if (from1 == short.class) { + return short.class; + } else if (from1 == char.class) { + return int.class; + } else if (from1 == int.class) { if (const1 != null) { final int constant = (int)const1; if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) { - return definition.shortType; + return short.class; } } - return definition.intType; + return int.class; } - } else if (sort0 == char.class) { - if (sort1 == byte.class) { - return definition.intType; - } else if (sort1 == short.class) { - return definition.intType; - } else if (sort1 == char.class) { - return definition.charType; - } else if (sort1 == int.class) { + } else if (from0 == char.class) { + if (from1 == byte.class) { + return int.class; + } else if (from1 == short.class) { + return int.class; + } else if (from1 == char.class) { + return char.class; + } else if (from1 == int.class) { if (const1 != null) { final int constant = (int)const1; if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; + return int.class; } - } else if (sort0 == int.class) { - if (sort1 == byte.class) { + } else if (from0 == int.class) { + if (from1 == byte.class) { if (const0 != null) { final int constant = (int)const0; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; - } else if (sort1 == short.class) { + return int.class; + } else if (from1 == short.class) { if (const0 != null) { final int constant = (int)const0; if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; - } else if (sort1 == char.class) { + return int.class; + } else if (from1 == char.class) { if (const0 != null) { final int constant = (int)const0; if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; - } else if (sort1 == int.class) { - return definition.intType; + return int.class; + } else if (from1 == int.class) { + return int.class; } } } @@ -737,6 +709,10 @@ public final class AnalyzerCaster { // TODO: to calculate the highest upper bound for the two types and return that. // TODO: However, for now we just return objectType that may require an extra cast. - return definition.ObjectType; + return Object.class; + } + + private AnalyzerCaster() { + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java index 7729c5319ea..36c072570ec 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java @@ -27,6 +27,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -76,6 +77,13 @@ public final class Definition { public final Type ArrayListType; public final Type HashMapType; + /** Marker class for def type to be used during type analysis. */ + public static final class def { + private def() { + + } + } + public static final class Type { public final String name; public final int dimensions; @@ -365,40 +373,41 @@ public final class Definition { } public static class Cast { + /** Create a standard cast with no boxing/unboxing. */ - public static Cast standard(Type from, Type to, boolean explicit) { + public static Cast standard(Class from, Class to, boolean explicit) { return new Cast(from, to, explicit, null, null, null, null); } /** Create a cast where the from type will be unboxed, and then the cast will be performed. */ - public static Cast unboxFrom(Type from, Type to, boolean explicit, Type unboxFrom) { + public static Cast unboxFrom(Class from, Class to, boolean explicit, Class unboxFrom) { return new Cast(from, to, explicit, unboxFrom, null, null, null); } /** Create a cast where the to type will be unboxed, and then the cast will be performed. */ - public static Cast unboxTo(Type from, Type to, boolean explicit, Type unboxTo) { + public static Cast unboxTo(Class from, Class to, boolean explicit, Class unboxTo) { return new Cast(from, to, explicit, null, unboxTo, null, null); } /** Create a cast where the from type will be boxed, and then the cast will be performed. */ - public static Cast boxFrom(Type from, Type to, boolean explicit, Type boxFrom) { + public static Cast boxFrom(Class from, Class to, boolean explicit, Class boxFrom) { return new Cast(from, to, explicit, null, null, boxFrom, null); } /** Create a cast where the to type will be boxed, and then the cast will be performed. */ - public static Cast boxTo(Type from, Type to, boolean explicit, Type boxTo) { + public static Cast boxTo(Class from, Class to, boolean explicit, Class boxTo) { return new Cast(from, to, explicit, null, null, null, boxTo); } - public final Type from; - public final Type to; + public final Class from; + public final Class to; public final boolean explicit; - public final Type unboxFrom; - public final Type unboxTo; - public final Type boxFrom; - public final Type boxTo; + public final Class unboxFrom; + public final Class unboxTo; + public final Class boxFrom; + public final Class boxTo; - private Cast(Type from, Type to, boolean explicit, Type unboxFrom, Type unboxTo, Type boxFrom, Type boxTo) { + private Cast(Class from, Class to, boolean explicit, Class unboxFrom, Class unboxTo, Class boxFrom, Class boxTo) { this.from = from; this.to = to; this.explicit = explicit; @@ -499,6 +508,124 @@ public final class Definition { constant.clazz == String.class; } + public static Class ObjectClassTodefClass(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == Object.class) { + char[] braces = new char[dimensions]; + Arrays.fill(braces, '['); + + String descriptor = new String(braces) + org.objectweb.asm.Type.getType(def.class).getDescriptor(); + org.objectweb.asm.Type type = org.objectweb.asm.Type.getType(descriptor); + + try { + return Class.forName(type.getInternalName().replace('/', '.')); + } catch (ClassNotFoundException exception) { + throw new IllegalStateException("internal error", exception); + } + } + } else if (clazz == Object.class) { + return def.class; + } + + return clazz; + } + + public static Class defClassToObjectClass(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == def.class) { + char[] braces = new char[dimensions]; + Arrays.fill(braces, '['); + + String descriptor = new String(braces) + org.objectweb.asm.Type.getType(Object.class).getDescriptor(); + org.objectweb.asm.Type type = org.objectweb.asm.Type.getType(descriptor); + + try { + return Class.forName(type.getInternalName().replace('/', '.')); + } catch (ClassNotFoundException exception) { + throw new IllegalStateException("internal error", exception); + } + } + } else if (clazz == def.class) { + return Object.class; + } + + return clazz; + } + + public static String ClassToName(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == def.class) { + StringBuilder builder = new StringBuilder("def"); + + for (int dimension = 0; dimension < dimensions; dimensions++) { + builder.append("[]"); + } + + return builder.toString(); + } + } else if (clazz == def.class) { + return "def"; + } + + return clazz.getCanonicalName().replace('$', '.'); + } + + public Type ClassToType(Class clazz) { + if (clazz == null) { + return null; + } else if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (clazz == def.class) { + return getType(structsMap.get("def"), dimensions); + } else { + return getType(runtimeMap.get(clazz).struct, dimensions); + } + } else if (clazz == def.class) { + return getType(structsMap.get("def"), 0); + } + + return getType(structsMap.get(ClassToName(clazz)), 0); + } + + public static Class TypeToClass (Type type) { + if (type.dynamic) { + return ObjectClassTodefClass(type.clazz); + } + + return type.clazz; + } + public RuntimeClass getRuntimeClass(Class clazz) { return runtimeMap.get(clazz); } @@ -536,8 +663,6 @@ public final class Definition { private final Map structsMap; private final Map simpleTypesMap; - public AnalyzerCaster caster; - public Definition(List whitelists) { structsMap = new HashMap<>(); simpleTypesMap = new HashMap<>(); @@ -719,8 +844,6 @@ public final class Definition { IteratorType = getType("Iterator"); ArrayListType = getType("ArrayList"); HashMapType = getType("HashMap"); - - caster = new AnalyzerCaster(this); } private void addStruct(ClassLoader whitelistClassLoader, Whitelist.Struct whitelistStruct) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java index b0c15abbfb0..7925856656e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java @@ -20,15 +20,17 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Cast; -import org.elasticsearch.painless.Definition.Type; +import org.elasticsearch.painless.Definition.def; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.Deque; import java.util.List; @@ -128,68 +130,68 @@ public final class MethodWriter extends GeneratorAdapter { mark(end); } - public void writeCast(final Cast cast) { + public void writeCast(Cast cast) { if (cast != null) { - if (cast.from.clazz == char.class && cast.to.clazz == String.class) { + if (cast.from == char.class && cast.to == String.class) { invokeStatic(UTILITY_TYPE, CHAR_TO_STRING); - } else if (cast.from.clazz == String.class && cast.to.clazz == char.class) { + } else if (cast.from == String.class && cast.to == char.class) { invokeStatic(UTILITY_TYPE, STRING_TO_CHAR); } else if (cast.unboxFrom != null) { - unbox(cast.unboxFrom.type); + unbox(getType(cast.unboxFrom)); writeCast(cast.from, cast.to); } else if (cast.unboxTo != null) { - if (cast.from.dynamic) { + if (cast.from == def.class) { if (cast.explicit) { - if (cast.to.clazz == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (cast.to.clazz == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT); - else if (cast.to.clazz == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT); - else if (cast.to.clazz == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT); - else if (cast.to.clazz == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT); - else if (cast.to.clazz == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT); - else if (cast.to.clazz == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT); - else if (cast.to.clazz == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT); + if (cast.to == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); + else if (cast.to == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT); + else if (cast.to == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT); + else if (cast.to == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT); + else if (cast.to == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT); + else if (cast.to == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT); + else if (cast.to == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT); + else if (cast.to == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT); else { throw new IllegalStateException("Illegal tree structure."); } } else { - if (cast.to.clazz == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (cast.to.clazz == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT); - else if (cast.to.clazz == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT); - else if (cast.to.clazz == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT); - else if (cast.to.clazz == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT); - else if (cast.to.clazz == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT); - else if (cast.to.clazz == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT); - else if (cast.to.clazz == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT); + if (cast.to == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); + else if (cast.to == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT); + else if (cast.to == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT); + else if (cast.to == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT); + else if (cast.to == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT); + else if (cast.to == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT); + else if (cast.to == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT); + else if (cast.to == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT); else { throw new IllegalStateException("Illegal tree structure."); } } } else { writeCast(cast.from, cast.to); - unbox(cast.unboxTo.type); + unbox(getType(cast.unboxTo)); } } else if (cast.boxFrom != null) { - box(cast.boxFrom.type); + box(getType(cast.boxFrom)); writeCast(cast.from, cast.to); } else if (cast.boxTo != null) { writeCast(cast.from, cast.to); - box(cast.boxTo.type); + box(getType(cast.boxTo)); } else { writeCast(cast.from, cast.to); } } } - private void writeCast(final Type from, final Type to) { + private void writeCast(Class from, Class to) { if (from.equals(to)) { return; } - if (from.clazz != boolean.class && from.clazz.isPrimitive() && to.clazz != boolean.class && to.clazz.isPrimitive()) { - cast(from.type, to.type); + if (from != boolean.class && from.isPrimitive() && to != boolean.class && to.isPrimitive()) { + cast(getType(from), getType(to)); } else { - if (!to.clazz.isAssignableFrom(from.clazz)) { - checkCast(to.type); + if (!to.isAssignableFrom(from)) { + checkCast(getType(to)); } } } @@ -202,6 +204,29 @@ public final class MethodWriter extends GeneratorAdapter { valueOf(type); } + public static Type getType(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == def.class) { + char[] braces = new char[dimensions]; + Arrays.fill(braces, '['); + + return Type.getType(new String(braces) + Type.getType(Object.class).getDescriptor()); + } + } else if (clazz == def.class) { + return Type.getType(Object.class); + } + + return Type.getType(clazz); + } + public void writeBranch(final Label tru, final Label fals) { if (tru != null) { visitJumpInsn(Opcodes.IFNE, tru); @@ -227,7 +252,7 @@ public final class MethodWriter extends GeneratorAdapter { } } - public void writeAppendStrings(final Type type) { + public void writeAppendStrings(final Definition.Type type) { if (INDY_STRING_CONCAT_BOOTSTRAP_HANDLE != null) { // Java 9+: record type information stringConcatArgs.peek().add(type.type); @@ -267,7 +292,7 @@ public final class MethodWriter extends GeneratorAdapter { } /** Writes a dynamic binary instruction: returnType, lhs, and rhs can be different */ - public void writeDynamicBinaryInstruction(Location location, Type returnType, Type lhs, Type rhs, + public void writeDynamicBinaryInstruction(Location location, Definition.Type returnType, Definition.Type lhs, Definition.Type rhs, Operation operation, int flags) { org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(returnType.type, lhs.type, rhs.type); @@ -318,7 +343,7 @@ public final class MethodWriter extends GeneratorAdapter { } /** Writes a static binary instruction */ - public void writeBinaryInstruction(Location location, Type type, Operation operation) { + public void writeBinaryInstruction(Location location, Definition.Type type, Operation operation) { if ((type.clazz == float.class || type.clazz == double.class) && (operation == Operation.LSH || operation == Operation.USH || operation == Operation.RSH || operation == Operation.BWAND || diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java index 2ca0b265430..eaa13ea9a8b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java @@ -119,7 +119,8 @@ public abstract class AExpression extends ANode { * @return The new child node for the parent node calling this method. */ AExpression cast(Locals locals) { - Cast cast = locals.getDefinition().caster.getLegalCast(location, actual, expected, explicit, internal); + Cast cast = + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(actual), Definition.TypeToClass(expected), explicit, internal); if (cast == null) { if (constant == null || this instanceof EConstant) { @@ -167,7 +168,7 @@ public abstract class AExpression extends ANode { // from this node because the output data for the EConstant // will already be the same. - constant = locals.getDefinition().caster.constCast(location, constant, cast); + constant = AnalyzerCaster.constCast(location, constant, cast); EConstant econstant = new EConstant(location, constant); econstant.analyze(locals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index 873f109e72d..45ca4601e96 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -19,7 +19,10 @@ package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Globals; @@ -139,33 +142,41 @@ public final class EAssignment extends AExpression { boolean shift = false; if (operation == Operation.MUL) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.DIV) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.REM) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.ADD) { - promote = locals.getDefinition().caster.promoteAdd(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteAdd(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else if (operation == Operation.SUB) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.LSH) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, false); - shiftDistance = locals.getDefinition().caster.promoteNumeric(rhs.actual, false); + promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); + shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shift = true; } else if (operation == Operation.RSH) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, false); - shiftDistance = locals.getDefinition().caster.promoteNumeric(rhs.actual, false); + promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); + shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shift = true; } else if (operation == Operation.USH) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, false); - shiftDistance = locals.getDefinition().caster.promoteNumeric(rhs.actual, false); + promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); + shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shift = true; } else if (operation == Operation.BWAND) { - promote = locals.getDefinition().caster.promoteXor(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else if (operation == Operation.XOR) { - promote = locals.getDefinition().caster.promoteXor(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else if (operation == Operation.BWOR) { - promote = locals.getDefinition().caster.promoteXor(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else { throw createError(new IllegalStateException("Illegal tree structure.")); } @@ -199,8 +210,8 @@ public final class EAssignment extends AExpression { rhs = rhs.cast(locals); - there = locals.getDefinition().caster.getLegalCast(location, lhs.actual, promote, false, false); - back = locals.getDefinition().caster.getLegalCast(location, promote, lhs.actual, true, false); + there = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(lhs.actual), Definition.TypeToClass(promote), false, false); + back = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(promote), Definition.TypeToClass(lhs.actual), true, false); this.statement = true; this.actual = read ? lhs.actual : locals.getDefinition().voidType; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index df92d72a3c0..55c2145acd8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -19,6 +19,7 @@ package org.elasticsearch.painless.node; +import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Type; @@ -101,7 +102,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply multiply [*] to types " + @@ -145,7 +147,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply divide [/] to types " + @@ -194,7 +197,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply remainder [%] to types " + @@ -243,7 +247,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteAdd(left.actual, right.actual); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteAdd(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promote == null) { throw createError(new ClassCastException("Cannot apply add [+] to types " + @@ -303,7 +308,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply subtract [-] to types " + @@ -362,8 +368,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - Type lhspromote = variables.getDefinition().caster.promoteNumeric(left.actual, false); - Type rhspromote = variables.getDefinition().caster.promoteNumeric(right.actual, false); + Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); + Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); if (lhspromote == null || rhspromote == null) { throw createError(new ClassCastException("Cannot apply left shift [<<] to types " + @@ -411,8 +417,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - Type lhspromote = variables.getDefinition().caster.promoteNumeric(left.actual, false); - Type rhspromote = variables.getDefinition().caster.promoteNumeric(right.actual, false); + Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); + Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); if (lhspromote == null || rhspromote == null) { throw createError(new ClassCastException("Cannot apply right shift [>>] to types " + @@ -460,8 +466,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - Type lhspromote = variables.getDefinition().caster.promoteNumeric(left.actual, false); - Type rhspromote = variables.getDefinition().caster.promoteNumeric(right.actual, false); + Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); + Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); actual = promote = lhspromote; shiftDistance = rhspromote; @@ -509,7 +515,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, false); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false)); if (promote == null) { throw createError(new ClassCastException("Cannot apply and [&] to types " + @@ -550,7 +557,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteXor(left.actual, right.actual); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promote == null) { throw createError(new ClassCastException("Cannot apply xor [^] to types " + @@ -592,7 +600,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, false); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false)); if (promote == null) { throw createError(new ClassCastException("Cannot apply or [|] to types " + diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java index 564fcef8eef..e736b2779f9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java @@ -82,11 +82,12 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) { Definition.Type from = ref.interfaceMethod.arguments.get(i); Definition.Type to = ref.delegateMethod.arguments.get(i); - locals.getDefinition().caster.getLegalCast(location, from, to, false, true); + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(from), Definition.TypeToClass(to), false, true); } if (ref.interfaceMethod.rtn.equals(locals.getDefinition().voidType) == false) { - locals.getDefinition().caster.getLegalCast(location, ref.delegateMethod.rtn, ref.interfaceMethod.rtn, false, true); + AnalyzerCaster.getLegalCast(location, + Definition.TypeToClass(ref.delegateMethod.rtn), Definition.TypeToClass(ref.interfaceMethod.rtn), false, true); } } catch (IllegalArgumentException e) { throw createError(e); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index 5c2a1498761..42ec197c7f5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java @@ -19,6 +19,7 @@ package org.elasticsearch.painless.node; +import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; import java.util.Objects; @@ -63,6 +64,6 @@ final class ECast extends AExpression { @Override public String toString() { - return singleLineToString(cast.to, child); + return singleLineToString(Definition.ClassToName(cast.to), child); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 020ea48cd4c..a7bb57a1a35 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -89,7 +89,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply equals [==] to types " + @@ -140,7 +141,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply reference equals [===] to types " + @@ -182,7 +184,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply not equals [!=] to types " + @@ -233,7 +236,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " + @@ -275,7 +279,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " + @@ -316,7 +321,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply greater than [>] to types " + @@ -357,7 +363,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " + @@ -398,7 +405,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply less than [>=] to types " + diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java index 571e57cad24..30a3d0d773f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java @@ -79,7 +79,8 @@ public final class EConditional extends AExpression { right.analyze(locals); if (expected == null) { - final Type promote = locals.getDefinition().caster.promoteConditional(left.actual, right.actual, left.constant, right.constant); + Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional( + Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), left.constant, right.constant)); left.expected = promote; right.expected = promote; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java index e9816c524bf..6005a326fe9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java @@ -20,6 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; @@ -81,7 +82,8 @@ public class EElvis extends AExpression { } if (expected == null) { - final Type promote = locals.getDefinition().caster.promoteConditional(lhs.actual, rhs.actual, lhs.constant, rhs.constant); + Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional( + Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), lhs.constant, rhs.constant)); lhs.expected = promote; rhs.expected = promote; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index ffbb344f29c..13289809e49 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -82,11 +82,12 @@ public final class EFunctionRef extends AExpression implements ILambda { for (int i = 0; i < interfaceMethod.arguments.size(); ++i) { Definition.Type from = interfaceMethod.arguments.get(i); Definition.Type to = delegateMethod.arguments.get(i); - locals.getDefinition().caster.getLegalCast(location, from, to, false, true); + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(from), Definition.TypeToClass(to), false, true); } if (interfaceMethod.rtn.equals(locals.getDefinition().voidType) == false) { - locals.getDefinition().caster.getLegalCast(location, delegateMethod.rtn, interfaceMethod.rtn, false, true); + AnalyzerCaster.getLegalCast( + location, Definition.TypeToClass(delegateMethod.rtn), Definition.TypeToClass(interfaceMethod.rtn), false, true); } } else { // whitelist lookup diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index 07de9138e7c..68950f5ea2a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -192,11 +192,12 @@ public final class ELambda extends AExpression implements ILambda { for (int i = 0; i < interfaceMethod.arguments.size(); ++i) { Type from = interfaceMethod.arguments.get(i); Type to = desugared.parameters.get(i + captures.size()).type; - locals.getDefinition().caster.getLegalCast(location, from, to, false, true); + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(from), Definition.TypeToClass(to), false, true); } if (interfaceMethod.rtn.equals(locals.getDefinition().voidType) == false) { - locals.getDefinition().caster.getLegalCast(location, desugared.rtnType, interfaceMethod.rtn, false, true); + AnalyzerCaster.getLegalCast( + location, Definition.TypeToClass(desugared.rtnType), Definition.TypeToClass(interfaceMethod.rtn), false, true); } actual = expected; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index e9971b538f5..aa81407819e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -90,7 +90,7 @@ public final class EUnary extends AExpression { void analyzeBWNot(Locals variables) { child.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(child.actual, false); + promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), false)); if (promote == null) { throw createError(new ClassCastException("Cannot apply not [~] to type [" + child.actual.name + "].")); @@ -121,7 +121,7 @@ public final class EUnary extends AExpression { void analyzerAdd(Locals variables) { child.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(child.actual, true); + promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply positive [+] to type [" + child.actual.name + "].")); @@ -156,7 +156,7 @@ public final class EUnary extends AExpression { void analyzerSub(Locals variables) { child.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(child.actual, true); + promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply negative [-] to type [" + child.actual.name + "].")); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java index 09c73c525be..a4c2eb8cd22 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java @@ -64,13 +64,10 @@ final class SSubEachArray extends AStatement { void analyze(Locals locals) { // We must store the array and index as variables for securing slots on the stack, and // also add the location offset to make the names unique in case of nested for each loops. - array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), - true); - index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), - true); - indexed = locals.getDefinition().getType(expression.actual.struct, - expression.actual.dimensions - 1); - cast = locals.getDefinition().caster.getLegalCast(location, indexed, variable.type, true, true); + array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), true); + index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), true); + indexed = locals.getDefinition().getType(expression.actual.struct, expression.actual.dimensions - 1); + cast = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(indexed), Definition.TypeToClass(variable.type), true, true); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java index a51a459f0f3..26fb4a2f845 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java @@ -25,6 +25,7 @@ import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.MethodKey; +import org.elasticsearch.painless.Definition.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; @@ -85,7 +86,7 @@ final class SSubEachIterable extends AStatement { } } - cast = locals.getDefinition().caster.getLegalCast(location, locals.getDefinition().DefType, variable.type, true, true); + cast = AnalyzerCaster.getLegalCast(location, def.class, Definition.TypeToClass(variable.type), true, true); } @Override diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java index 919b0881c07..69abc3481a1 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java @@ -20,7 +20,6 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Cast; -import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.test.ESTestCase; @@ -28,73 +27,73 @@ public class AnalyzerCasterTests extends ESTestCase { private static final Definition definition = new Definition(Whitelist.BASE_WHITELISTS); - private static void assertCast(Type actual, Type expected, boolean mustBeExplicit) { + private static void assertCast(Class actual, Class expected, boolean mustBeExplicit) { Location location = new Location("dummy", 0); if (actual.equals(expected)) { assertFalse(mustBeExplicit); - assertNull(definition.caster.getLegalCast(location, actual, expected, false, false)); - assertNull(definition.caster.getLegalCast(location, actual, expected, true, false)); + assertNull(AnalyzerCaster.getLegalCast(location, actual, expected, false, false)); + assertNull(AnalyzerCaster.getLegalCast(location, actual, expected, true, false)); return; } - Cast cast = definition.caster.getLegalCast(location, actual, expected, true, false); + Cast cast = AnalyzerCaster.getLegalCast(location, actual, expected, true, false); assertEquals(actual, cast.from); assertEquals(expected, cast.to); if (mustBeExplicit) { ClassCastException error = expectThrows(ClassCastException.class, - () -> definition.caster.getLegalCast(location, actual, expected, false, false)); + () -> AnalyzerCaster.getLegalCast(location, actual, expected, false, false)); assertTrue(error.getMessage().startsWith("Cannot cast")); } else { - cast = definition.caster.getLegalCast(location, actual, expected, false, false); + cast = AnalyzerCaster.getLegalCast(location, actual, expected, false, false); assertEquals(actual, cast.from); assertEquals(expected, cast.to); } } public void testNumericCasts() { - assertCast(definition.byteType, definition.byteType, false); - assertCast(definition.byteType, definition.shortType, false); - assertCast(definition.byteType, definition.intType, false); - assertCast(definition.byteType, definition.longType, false); - assertCast(definition.byteType, definition.floatType, false); - assertCast(definition.byteType, definition.doubleType, false); + assertCast(byte.class, byte.class, false); + assertCast(byte.class, short.class, false); + assertCast(byte.class, int.class, false); + assertCast(byte.class, long.class, false); + assertCast(byte.class, float.class, false); + assertCast(byte.class, double.class, false); - assertCast(definition.shortType, definition.byteType, true); - assertCast(definition.shortType, definition.shortType, false); - assertCast(definition.shortType, definition.intType, false); - assertCast(definition.shortType, definition.longType, false); - assertCast(definition.shortType, definition.floatType, false); - assertCast(definition.shortType, definition.doubleType, false); + assertCast(short.class, byte.class, true); + assertCast(short.class, short.class, false); + assertCast(short.class, int.class, false); + assertCast(short.class, long.class, false); + assertCast(short.class, float.class, false); + assertCast(short.class, double.class, false); - assertCast(definition.intType, definition.byteType, true); - assertCast(definition.intType, definition.shortType, true); - assertCast(definition.intType, definition.intType, false); - assertCast(definition.intType, definition.longType, false); - assertCast(definition.intType, definition.floatType, false); - assertCast(definition.intType, definition.doubleType, false); + assertCast(int.class, byte.class, true); + assertCast(int.class, short.class, true); + assertCast(int.class, int.class, false); + assertCast(int.class, long.class, false); + assertCast(int.class, float.class, false); + assertCast(int.class, double.class, false); - assertCast(definition.longType, definition.byteType, true); - assertCast(definition.longType, definition.shortType, true); - assertCast(definition.longType, definition.intType, true); - assertCast(definition.longType, definition.longType, false); - assertCast(definition.longType, definition.floatType, false); - assertCast(definition.longType, definition.doubleType, false); + assertCast(long.class, byte.class, true); + assertCast(long.class, short.class, true); + assertCast(long.class, int.class, true); + assertCast(long.class, long.class, false); + assertCast(long.class, float.class, false); + assertCast(long.class, double.class, false); - assertCast(definition.floatType, definition.byteType, true); - assertCast(definition.floatType, definition.shortType, true); - assertCast(definition.floatType, definition.intType, true); - assertCast(definition.floatType, definition.longType, true); - assertCast(definition.floatType, definition.floatType, false); - assertCast(definition.floatType, definition.doubleType, false); + assertCast(float.class, byte.class, true); + assertCast(float.class, short.class, true); + assertCast(float.class, int.class, true); + assertCast(float.class, long.class, true); + assertCast(float.class, float.class, false); + assertCast(float.class, double.class, false); - assertCast(definition.doubleType, definition.byteType, true); - assertCast(definition.doubleType, definition.shortType, true); - assertCast(definition.doubleType, definition.intType, true); - assertCast(definition.doubleType, definition.longType, true); - assertCast(definition.doubleType, definition.floatType, true); - assertCast(definition.doubleType, definition.doubleType, false); + assertCast(double.class, byte.class, true); + assertCast(double.class, short.class, true); + assertCast(double.class, int.class, true); + assertCast(double.class, long.class, true); + assertCast(double.class, float.class, true); + assertCast(double.class, double.class, false); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java index 424b0c286ec..fb1a004e3cd 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java @@ -162,12 +162,12 @@ public class NodeToStringTests extends ESTestCase { public void testECast() { Location l = new Location(getTestName(), 0); AExpression child = new EConstant(l, "test"); - Cast cast = Cast.standard(definition.StringType, definition.IntegerType, true); + Cast cast = Cast.standard(String.class, Integer.class, true); assertEquals("(ECast java.lang.Integer (EConstant String 'test'))", new ECast(l, child, cast).toString()); l = new Location(getTestName(), 1); child = new EBinary(l, Operation.ADD, new EConstant(l, "test"), new EConstant(l, 12)); - cast = Cast.standard(definition.IntegerType, definition.BooleanType, true); + cast = Cast.standard(Integer.class, Boolean.class, true); assertEquals("(ECast java.lang.Boolean (EBinary (EConstant String 'test') + (EConstant Integer 12)))", new ECast(l, child, cast).toString()); } diff --git a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml index 0e319be97bf..20047e7d482 100644 --- a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml +++ b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml @@ -137,4 +137,4 @@ - match: { error.root_cause.0.type: "remote_transport_exception" } - match: { error.type: "illegal_argument_exception" } - - match: { error.reason: "Object has already been built and is self-referencing itself" } + - match: { error.reason: "Iterable object is self-referencing itself" } diff --git a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml index 28679cb223f..b7be116b386 100644 --- a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml +++ b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml @@ -406,3 +406,39 @@ - match: { hits.hits.0._score: 1.0 } - match: { aggregations.value_agg.buckets.0.key: 2 } - match: { aggregations.value_agg.buckets.0.doc_count: 1 } + +--- +"Return self-referencing map": + - do: + indices.create: + index: test + body: + settings: + number_of_shards: "1" + + - do: + index: + index: test + type: test + id: 1 + body: { "genre": 1 } + + - do: + indices.refresh: {} + + - do: + catch: bad_request + index: test + search: + body: + aggs: + genre: + terms: + script: + lang: painless + source: "def x = [:] ; def y = [:] ; x.a = y ; y.a = x ; return x" + + - match: { error.root_cause.0.type: "illegal_argument_exception" } + - match: { error.root_cause.0.reason: "Iterable object is self-referencing itself" } + - match: { error.type: "search_phase_execution_exception" } + - match: { error.reason: "all shards failed" } diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java index 3ad48d803a4..f21fb45ed7a 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java @@ -91,6 +91,7 @@ public class CancelTests extends ReindexTestCase { int numDocs = getNumShards(INDEX).numPrimaries * 10 * builder.request().getSlices(); ALLOWED_OPERATIONS.release(numDocs); + logger.debug("setting up [{}] docs", numDocs); indexRandom(true, false, true, IntStream.range(0, numDocs) .mapToObj(i -> client().prepareIndex(INDEX, TYPE, String.valueOf(i)).setSource("n", i)) .collect(Collectors.toList())); @@ -102,16 +103,21 @@ public class CancelTests extends ReindexTestCase { // Scroll by 1 so that cancellation is easier to control builder.source().setSize(1); - /* Allow a random number of the documents less the number of workers to be modified by the reindex action. That way at least one - * worker is blocked. */ + /* Allow a random number of the documents less the number of workers + * to be modified by the reindex action. That way at least one worker + * is blocked. */ int numModifiedDocs = randomIntBetween(builder.request().getSlices() * 2, numDocs); + logger.debug("chose to modify [{}] docs", numModifiedDocs); ALLOWED_OPERATIONS.release(numModifiedDocs - builder.request().getSlices()); // Now execute the reindex action... ActionFuture future = builder.execute(); - /* ... and waits for the indexing operation listeners to block. It is important to realize that some of the workers might have - * exhausted their slice while others might have quite a bit left to work on. We can't control that. */ + /* ... and wait for the indexing operation listeners to block. It + * is important to realize that some of the workers might have + * exhausted their slice while others might have quite a bit left + * to work on. We can't control that. */ + logger.debug("waiting for updates to be blocked"); awaitBusy(() -> ALLOWED_OPERATIONS.hasQueuedThreads() && ALLOWED_OPERATIONS.availablePermits() == 0); // Status should show the task running @@ -128,15 +134,19 @@ public class CancelTests extends ReindexTestCase { cancelTasksResponse.rethrowFailures("Cancel"); assertThat(cancelTasksResponse.getTasks(), hasSize(1)); - // The status should now show canceled. The request will still be in the list because it is (or its children are) still blocked. + /* The status should now show canceled. The request will still be in the + * list because it is (or its children are) still blocked. */ mainTask = client().admin().cluster().prepareGetTask(mainTask.getTaskId()).get().getTask().getTask(); status = (BulkByScrollTask.Status) mainTask.getStatus(); + logger.debug("asserting that parent is marked canceled {}", status); assertEquals(CancelTasksRequest.DEFAULT_REASON, status.getReasonCancelled()); + if (builder.request().getSlices() > 1) { boolean foundCancelled = false; ListTasksResponse sliceList = client().admin().cluster().prepareListTasks().setParentTaskId(mainTask.getTaskId()) .setDetailed(true).get(); sliceList.rethrowFailures("Fetch slice tasks"); + logger.debug("finding at least one canceled child among {}", sliceList.getTasks()); for (TaskInfo slice: sliceList.getTasks()) { BulkByScrollTask.Status sliceStatus = (BulkByScrollTask.Status) slice.getStatus(); if (sliceStatus.getReasonCancelled() == null) continue; @@ -146,7 +156,7 @@ public class CancelTests extends ReindexTestCase { assertTrue("Didn't find at least one sub task that was cancelled", foundCancelled); } - // Unblock the last operations + logger.debug("unblocking the blocked update"); ALLOWED_OPERATIONS.release(builder.request().getSlices()); // Checks that no more operations are executed diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java index f101b125382..f5e234f66ca 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java @@ -107,6 +107,14 @@ public class ReindexFailureTests extends ReindexTestCase { response.get(); logger.info("Didn't trigger a reindex failure on the {} attempt", attempt); attempt++; + /* + * In the past we've seen the delete of the source index + * actually take effect *during* the `indexDocs` call in + * the next step. This breaks things pretty disasterously + * so we *try* and wait for the delete to be fully + * complete here. + */ + assertBusy(() -> assertFalse(client().admin().indices().prepareExists("source").get().isExists())); } catch (ExecutionException e) { logger.info("Triggered a reindex failure on the {} attempt: {}", attempt, e.getMessage()); assertThat(e.getMessage(), diff --git a/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java b/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java index 2b21a81d91f..d70ed9ea9aa 100644 --- a/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java +++ b/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java @@ -73,7 +73,7 @@ class InternalAwsS3Service extends AbstractLifecycleComponent implements AwsS3Se logger.debug("creating S3 client with client_name [{}], endpoint [{}]", clientName, clientSettings.endpoint); AWSCredentialsProvider credentials = buildCredentials(logger, deprecationLogger, clientSettings, repositorySettings); - ClientConfiguration configuration = buildConfiguration(clientSettings, repositorySettings); + ClientConfiguration configuration = buildConfiguration(clientSettings); client = new AmazonS3Client(credentials, configuration); @@ -86,7 +86,7 @@ class InternalAwsS3Service extends AbstractLifecycleComponent implements AwsS3Se } // pkg private for tests - static ClientConfiguration buildConfiguration(S3ClientSettings clientSettings, Settings repositorySettings) { + static ClientConfiguration buildConfiguration(S3ClientSettings clientSettings) { ClientConfiguration clientConfiguration = new ClientConfiguration(); // the response metadata cache is only there for diagnostics purposes, // but can force objects from every response to the old generation. diff --git a/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java b/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java index f85f2eb6f32..18c701f5fc1 100644 --- a/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java +++ b/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java @@ -95,7 +95,7 @@ public class AwsS3ServiceImplTests extends ESTestCase { } public void testAWSDefaultConfiguration() { - launchAWSConfigurationTest(Settings.EMPTY, Settings.EMPTY, Protocol.HTTPS, null, -1, null, null, 3, + launchAWSConfigurationTest(Settings.EMPTY, Protocol.HTTPS, null, -1, null, null, 3, ClientConfiguration.DEFAULT_THROTTLE_RETRIES, ClientConfiguration.DEFAULT_SOCKET_TIMEOUT); } @@ -110,7 +110,7 @@ public class AwsS3ServiceImplTests extends ESTestCase { .put("s3.client.default.proxy.port", 8080) .put("s3.client.default.read_timeout", "10s") .build(); - launchAWSConfigurationTest(settings, Settings.EMPTY, Protocol.HTTP, "aws_proxy_host", 8080, "aws_proxy_username", + launchAWSConfigurationTest(settings, Protocol.HTTP, "aws_proxy_host", 8080, "aws_proxy_username", "aws_proxy_password", 3, ClientConfiguration.DEFAULT_THROTTLE_RETRIES, 10000); } @@ -118,7 +118,7 @@ public class AwsS3ServiceImplTests extends ESTestCase { Settings settings = Settings.builder() .put("s3.client.default.max_retries", 5) .build(); - launchAWSConfigurationTest(settings, Settings.EMPTY, Protocol.HTTPS, null, -1, null, + launchAWSConfigurationTest(settings, Protocol.HTTPS, null, -1, null, null, 5, ClientConfiguration.DEFAULT_THROTTLE_RETRIES, 50000); } @@ -126,22 +126,21 @@ public class AwsS3ServiceImplTests extends ESTestCase { final boolean throttling = randomBoolean(); Settings settings = Settings.builder().put("s3.client.default.use_throttle_retries", throttling).build(); - launchAWSConfigurationTest(settings, Settings.EMPTY, Protocol.HTTPS, null, -1, null, null, 3, throttling, 50000); + launchAWSConfigurationTest(settings, Protocol.HTTPS, null, -1, null, null, 3, throttling, 50000); } private void launchAWSConfigurationTest(Settings settings, - Settings singleRepositorySettings, - Protocol expectedProtocol, - String expectedProxyHost, - int expectedProxyPort, - String expectedProxyUsername, - String expectedProxyPassword, - Integer expectedMaxRetries, - boolean expectedUseThrottleRetries, - int expectedReadTimeout) { + Protocol expectedProtocol, + String expectedProxyHost, + int expectedProxyPort, + String expectedProxyUsername, + String expectedProxyPassword, + Integer expectedMaxRetries, + boolean expectedUseThrottleRetries, + int expectedReadTimeout) { S3ClientSettings clientSettings = S3ClientSettings.getClientSettings(settings, "default"); - ClientConfiguration configuration = InternalAwsS3Service.buildConfiguration(clientSettings, singleRepositorySettings); + ClientConfiguration configuration = InternalAwsS3Service.buildConfiguration(clientSettings); assertThat(configuration.getResponseMetadataCacheSize(), is(0)); assertThat(configuration.getProtocol(), is(expectedProtocol)); diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml index aaf277d171b..e094c47ff42 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml @@ -7,6 +7,8 @@ setup: mappings: doc: properties: + date: + type: date keyword: type: keyword long: @@ -40,6 +42,20 @@ setup: id: 4 body: { "keyword": "bar", "long": [1000, 0] } + - do: + index: + index: test + type: doc + id: 5 + body: { "date": "2017-10-20T03:08:45" } + + - do: + index: + index: test + type: doc + id: 6 + body: { "date": "2017-10-21T07:00:00" } + - do: indices.refresh: index: [test] @@ -66,7 +82,7 @@ setup: } ] - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 2 } - match: { aggregations.test.buckets.0.key.kw: "bar" } - match: { aggregations.test.buckets.0.doc_count: 3 } @@ -104,7 +120,7 @@ setup: } ] - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 5 } - match: { aggregations.test.buckets.0.key.long: 0} - match: { aggregations.test.buckets.0.key.kw: "bar" } @@ -154,7 +170,7 @@ setup: ] after: { "long": 20, "kw": "foo" } - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 2 } - match: { aggregations.test.buckets.0.key.long: 100 } - match: { aggregations.test.buckets.0.key.kw: "bar" } @@ -188,7 +204,7 @@ setup: ] after: { "kw": "delta" } - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 1 } - match: { aggregations.test.buckets.0.key.kw: "foo" } - match: { aggregations.test.buckets.0.doc_count: 2 } @@ -220,3 +236,62 @@ setup: } } ] + +--- +"Composite aggregation with format": + - skip: + version: " - 6.99.99" + reason: this uses a new option (format) added in 7.0.0 + + - do: + search: + index: test + body: + aggregations: + test: + composite: + sources: [ + { + "date": { + "date_histogram": { + "field": "date", + "interval": "1d", + "format": "yyyy-MM-dd" + } + } + } + ] + + - match: {hits.total: 6} + - length: { aggregations.test.buckets: 2 } + - match: { aggregations.test.buckets.0.key.date: "2017-10-20" } + - match: { aggregations.test.buckets.0.doc_count: 1 } + - match: { aggregations.test.buckets.1.key.date: "2017-10-21" } + - match: { aggregations.test.buckets.1.doc_count: 1 } + + - do: + search: + index: test + body: + aggregations: + test: + composite: + after: { + date: "2017-10-20" + } + sources: [ + { + "date": { + "date_histogram": { + "field": "date", + "interval": "1d", + "format": "yyyy-MM-dd" + } + } + } + ] + + - match: {hits.total: 6} + - length: { aggregations.test.buckets: 1 } + - match: { aggregations.test.buckets.0.key.date: "2017-10-21" } + - match: { aggregations.test.buckets.0.doc_count: 1 } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java index 7b6c8f6eb6f..03c1308e1d9 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java @@ -32,6 +32,7 @@ import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; @@ -57,7 +58,7 @@ import static org.elasticsearch.action.ValidateActions.addValidationError; * @see org.elasticsearch.client.IndicesAdminClient#putMapping(PutMappingRequest) * @see PutMappingResponse */ -public class PutMappingRequest extends AcknowledgedRequest implements IndicesRequest.Replaceable { +public class PutMappingRequest extends AcknowledgedRequest implements IndicesRequest.Replaceable, ToXContentObject { private static ObjectHashSet RESERVED_FIELDS = ObjectHashSet.from( "_uid", "_id", "_type", "_source", "_all", "_analyzer", "_parent", "_routing", "_index", @@ -318,4 +319,14 @@ public class PutMappingRequest extends AcknowledgedRequest im } out.writeOptionalWriteable(concreteIndex); } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + if (source != null) { + builder.rawValue(new BytesArray(source), XContentType.JSON); + } else { + builder.startObject().endObject(); + } + return builder; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java index 64b3c77f050..f427a316c2e 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java @@ -22,13 +22,24 @@ package org.elasticsearch.action.admin.indices.mapping.put; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; /** * The response of put mapping operation. */ -public class PutMappingResponse extends AcknowledgedResponse { +public class PutMappingResponse extends AcknowledgedResponse implements ToXContentObject { + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("put_mapping", + true, args -> new PutMappingResponse((boolean) args[0])); + + static { + declareAcknowledgedField(PARSER); + } protected PutMappingResponse() { @@ -49,4 +60,16 @@ public class PutMappingResponse extends AcknowledgedResponse { super.writeTo(out); writeAcknowledged(out); } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + addAcknowledgedField(builder); + builder.endObject(); + return builder; + } + + public static PutMappingResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); + } } diff --git a/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java b/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java index 4632ef63174..b9e9f1ec483 100644 --- a/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java +++ b/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java @@ -122,14 +122,14 @@ abstract class AbstractSearchAsyncAction exten * at least one successful operation left and if so we move to the next phase. If not we immediately fail the * search phase as "all shards failed"*/ if (successfulOps.get() == 0) { // we have 0 successful results that means we shortcut stuff and return a failure + final ShardOperationFailedException[] shardSearchFailures = ExceptionsHelper.groupBy(buildShardFailures()); + Throwable cause = shardSearchFailures.length == 0 ? null : + ElasticsearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; if (logger.isDebugEnabled()) { - final ShardOperationFailedException[] shardSearchFailures = ExceptionsHelper.groupBy(buildShardFailures()); - Throwable cause = shardSearchFailures.length == 0 ? null : - ElasticsearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; logger.debug((Supplier) () -> new ParameterizedMessage("All shards failed for phase: [{}]", getName()), cause); } - onPhaseFailure(currentPhase, "all shards failed", null); + onPhaseFailure(currentPhase, "all shards failed", cause); } else { if (logger.isTraceEnabled()) { final String resultsFrom = results.getSuccessfulResults() diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java index 98afe41c596..23ed28569d2 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java @@ -276,11 +276,8 @@ public class MetaData implements Iterable, Diffable, To if (!filteredValues.isEmpty()) { // Make the list order deterministic CollectionUtil.timSort(filteredValues, Comparator.comparing(AliasMetaData::alias)); - mapBuilder.put(index, Collections.unmodifiableList(filteredValues)); - } else if (matchAllAliases) { - // in case all aliases are requested then it is desired to return the concrete index with no aliases (#25114): - mapBuilder.put(index, Collections.emptyList()); } + mapBuilder.put(index, Collections.unmodifiableList(filteredValues)); } return mapBuilder.build(); } diff --git a/server/src/main/java/org/elasticsearch/common/settings/Setting.java b/server/src/main/java/org/elasticsearch/common/settings/Setting.java index bc22dbb63eb..fd91a8a7601 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/Setting.java +++ b/server/src/main/java/org/elasticsearch/common/settings/Setting.java @@ -597,7 +597,7 @@ public class Setting implements ToXContentObject { @Override public boolean hasChanged(Settings current, Settings previous) { - return Stream.concat(matchStream(current), matchStream(previous)).findAny().isPresent(); + return current.filter(k -> match(k)).equals(previous.filter(k -> match(k))) == false; } @Override @@ -612,7 +612,7 @@ public class Setting implements ToXContentObject { if (updater.hasChanged(current, previous)) { // only the ones that have changed otherwise we might get too many updates // the hasChanged above checks only if there are any changes - T value = updater.getValue(current, previous); + T value = updater.getValue(current, previous); if ((omitDefaults && value.equals(concreteSetting.getDefault(current))) == false) { result.put(namespace, value); } diff --git a/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java b/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java index 54a49f7e4f2..08d02cdea31 100644 --- a/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java +++ b/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java @@ -19,16 +19,20 @@ package org.elasticsearch.common.util; +import java.nio.file.Path; import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.RandomAccess; +import java.util.Set; import com.carrotsearch.hppc.ObjectArrayList; import org.apache.lucene.util.BytesRef; @@ -221,6 +225,40 @@ public class CollectionUtils { return ints.stream().mapToInt(s -> s).toArray(); } + public static void ensureNoSelfReferences(Object value) { + Iterable it = convert(value); + if (it != null) { + ensureNoSelfReferences(it, value, Collections.newSetFromMap(new IdentityHashMap<>())); + } + } + + private static Iterable convert(Object value) { + if (value == null) { + return null; + } + if (value instanceof Map) { + return ((Map) value).values(); + } else if ((value instanceof Iterable) && (value instanceof Path == false)) { + return (Iterable) value; + } else if (value instanceof Object[]) { + return Arrays.asList((Object[]) value); + } else { + return null; + } + } + + private static void ensureNoSelfReferences(final Iterable value, Object originalReference, final Set ancestors) { + if (value != null) { + if (ancestors.add(originalReference) == false) { + throw new IllegalArgumentException("Iterable object is self-referencing itself"); + } + for (Object o : value) { + ensureNoSelfReferences(convert(o), o, ancestors); + } + ancestors.remove(originalReference); + } + } + private static class RotatedList extends AbstractList implements RandomAccess { private final List in; diff --git a/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java b/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java index 070510e13ff..9f7603c997e 100644 --- a/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java +++ b/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.lease.Releasable; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.util.CollectionUtils; import org.joda.time.DateTimeZone; import org.joda.time.ReadableInstant; import org.joda.time.format.DateTimeFormatter; @@ -43,7 +44,6 @@ import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.IdentityHashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -780,7 +780,6 @@ public final class XContentBuilder implements Releasable, Flushable { if (values == null) { return nullValue(); } - return value(Arrays.asList(values), ensureNoSelfReferences); } @@ -865,7 +864,7 @@ public final class XContentBuilder implements Releasable, Flushable { // checks that the map does not contain references to itself because // iterating over map entries will cause a stackoverflow error if (ensureNoSelfReferences) { - ensureNoSelfReferences(values); + CollectionUtils.ensureNoSelfReferences(values); } startObject(); @@ -894,9 +893,8 @@ public final class XContentBuilder implements Releasable, Flushable { // checks that the iterable does not contain references to itself because // iterating over entries will cause a stackoverflow error if (ensureNoSelfReferences) { - ensureNoSelfReferences(values); + CollectionUtils.ensureNoSelfReferences(values); } - startArray(); for (Object value : values) { // pass ensureNoSelfReferences=false as we already performed the check at a higher level @@ -1067,32 +1065,4 @@ public final class XContentBuilder implements Releasable, Flushable { throw new IllegalArgumentException(message); } } - - static void ensureNoSelfReferences(Object value) { - ensureNoSelfReferences(value, Collections.newSetFromMap(new IdentityHashMap<>())); - } - - private static void ensureNoSelfReferences(final Object value, final Set ancestors) { - if (value != null) { - - Iterable it; - if (value instanceof Map) { - it = ((Map) value).values(); - } else if ((value instanceof Iterable) && (value instanceof Path == false)) { - it = (Iterable) value; - } else if (value instanceof Object[]) { - it = Arrays.asList((Object[]) value); - } else { - return; - } - - if (ancestors.add(value) == false) { - throw new IllegalArgumentException("Object has already been built and is self-referencing itself"); - } - for (Object o : it) { - ensureNoSelfReferences(o, ancestors); - } - ancestors.remove(value); - } - } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java index 5b36063e17a..58a15bbb366 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java @@ -147,17 +147,15 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder sourceNames = new ArrayList<>(); for (int i = 0; i < configs.length; i++) { configs[i] = sources.get(i).build(context, i, configs.length, sortFields[i]); - sourceNames.add(sources.get(i).name()); if (configs[i].valuesSource().needsScores()) { throw new IllegalArgumentException("[sources] cannot access _score"); } } final CompositeKey afterKey; if (after != null) { - if (after.size() != sources.size()) { + if (after.size() != configs.length) { throw new IllegalArgumentException("[after] has " + after.size() + " value(s) but [sources] has " + sources.size()); } @@ -179,7 +177,7 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder { private final int size; private final CompositeValuesSourceConfig[] sources; - private final List sourceNames; private final CompositeKey afterKey; CompositeAggregationFactory(String name, SearchContext context, AggregatorFactory parent, AggregatorFactories.Builder subFactoriesBuilder, Map metaData, - int size, CompositeValuesSourceConfig[] sources, - List sourceNames, CompositeKey afterKey) throws IOException { + int size, CompositeValuesSourceConfig[] sources, CompositeKey afterKey) throws IOException { super(name, context, parent, subFactoriesBuilder, metaData); this.size = size; this.sources = sources; - this.sourceNames = sourceNames; this.afterKey = afterKey; } @@ -50,6 +47,6 @@ class CompositeAggregationFactory extends AggregatorFactory pipelineAggregators, Map metaData) throws IOException { return new CompositeAggregator(name, factories, context, parent, pipelineAggregators, metaData, - size, sources, sourceNames, afterKey); + size, sources, afterKey); } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java index 3467aaf318b..e822480f915 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.RoaringDocIdSet; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.InternalAggregation; @@ -43,11 +44,13 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.stream.Collectors; final class CompositeAggregator extends BucketsAggregator { private final int size; private final CompositeValuesSourceConfig[] sources; private final List sourceNames; + private final List formats; private final boolean canEarlyTerminate; private final TreeMap keys; @@ -59,12 +62,12 @@ final class CompositeAggregator extends BucketsAggregator { CompositeAggregator(String name, AggregatorFactories factories, SearchContext context, Aggregator parent, List pipelineAggregators, Map metaData, - int size, CompositeValuesSourceConfig[] sources, List sourceNames, - CompositeKey rawAfterKey) throws IOException { + int size, CompositeValuesSourceConfig[] sources, CompositeKey rawAfterKey) throws IOException { super(name, factories, context, parent, pipelineAggregators, metaData); this.size = size; this.sources = sources; - this.sourceNames = sourceNames; + this.sourceNames = Arrays.stream(sources).map(CompositeValuesSourceConfig::name).collect(Collectors.toList()); + this.formats = Arrays.stream(sources).map(CompositeValuesSourceConfig::format).collect(Collectors.toList()); // we use slot 0 to fill the current document (size+1). this.array = new CompositeValuesComparator(context.searcher().getIndexReader(), sources, size+1); if (rawAfterKey != null) { @@ -131,15 +134,17 @@ final class CompositeAggregator extends BucketsAggregator { CompositeKey key = array.toCompositeKey(slot); InternalAggregations aggs = bucketAggregations(slot); int docCount = bucketDocCount(slot); - buckets[pos++] = new InternalComposite.InternalBucket(sourceNames, key, reverseMuls, docCount, aggs); + buckets[pos++] = new InternalComposite.InternalBucket(sourceNames, formats, key, reverseMuls, docCount, aggs); } - return new InternalComposite(name, size, sourceNames, Arrays.asList(buckets), reverseMuls, pipelineAggregators(), metaData()); + return new InternalComposite(name, size, sourceNames, formats, Arrays.asList(buckets), reverseMuls, + pipelineAggregators(), metaData()); } @Override public InternalAggregation buildEmptyAggregation() { final int[] reverseMuls = getReverseMuls(); - return new InternalComposite(name, size, sourceNames, Collections.emptyList(), reverseMuls, pipelineAggregators(), metaData()); + return new InternalComposite(name, size, sourceNames, formats, Collections.emptyList(), reverseMuls, + pipelineAggregators(), metaData()); } @Override diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java index 849fe2c513e..0ce87460a54 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java @@ -56,7 +56,7 @@ final class CompositeValuesComparator { if (vs.isFloatingPoint()) { arrays[i] = CompositeValuesSource.wrapDouble(vs, size, reverseMul); } else { - arrays[i] = CompositeValuesSource.wrapLong(vs, size, reverseMul); + arrays[i] = CompositeValuesSource.wrapLong(vs, sources[i].format(), size, reverseMul); } } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java index 88d54744777..2d0368dfd4d 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java @@ -23,8 +23,10 @@ import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.index.fielddata.SortedBinaryDocValues; import org.elasticsearch.index.fielddata.SortedNumericDoubleValues; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.support.ValuesSource; import org.elasticsearch.search.sort.SortOrder; @@ -96,8 +98,9 @@ abstract class CompositeValuesSource wrapLong(ValuesSource.Numeric vs, int size, int reverseMul) { - return new LongValuesSource(vs, size, reverseMul); + static CompositeValuesSource wrapLong(ValuesSource.Numeric vs, DocValueFormat format, + int size, int reverseMul) { + return new LongValuesSource(vs, format, size, reverseMul); } /** @@ -273,9 +276,12 @@ abstract class CompositeValuesSource { private final long[] values; + // handles "format" for date histogram source + private final DocValueFormat format; - LongValuesSource(ValuesSource.Numeric vs, int size, int reverseMul) { + LongValuesSource(ValuesSource.Numeric vs, DocValueFormat format, int size, int reverseMul) { super(vs, size, reverseMul); + this.format = format; this.values = new long[size]; } @@ -304,7 +310,11 @@ abstract class CompositeValuesSource { + throw new IllegalArgumentException("now() is not supported in [after] key"); + }); } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java index 2652d90f8c3..85d172907e0 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java @@ -25,6 +25,7 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.search.SortField; +import org.elasticsearch.Version; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; @@ -51,6 +52,7 @@ public abstract class CompositeValuesSourceBuilder config = ValuesSourceConfig.resolve(context.getQueryShardContext(), - valueType, field, script, missing, null, null); + valueType, field, script, missing, null, format); return innerBuild(context, config, pos, numPos, sortField); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java index 4d5c1c8c846..ee70d3f39a5 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java @@ -19,30 +19,47 @@ package org.elasticsearch.search.aggregations.bucket.composite; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.support.ValuesSource; import org.elasticsearch.search.sort.SortOrder; class CompositeValuesSourceConfig { private final String name; private final ValuesSource vs; + private final DocValueFormat format; private final int reverseMul; private final boolean canEarlyTerminate; - CompositeValuesSourceConfig(String name, ValuesSource vs, SortOrder order, boolean canEarlyTerminate) { + CompositeValuesSourceConfig(String name, ValuesSource vs, DocValueFormat format, SortOrder order, boolean canEarlyTerminate) { this.name = name; this.vs = vs; + this.format = format; this.canEarlyTerminate = canEarlyTerminate; this.reverseMul = order == SortOrder.ASC ? 1 : -1; } + /** + * Returns the name associated with this configuration. + */ String name() { return name; } + /** + * Returns the {@link ValuesSource} for this configuration. + */ ValuesSource valuesSource() { return vs; } + /** + * The {@link DocValueFormat} to use for formatting the keys. + * {@link DocValueFormat#RAW} means no formatting. + */ + DocValueFormat format() { + return format; + } + /** * The sort order for the values source (e.g. -1 for descending and 1 for ascending). */ @@ -51,6 +68,9 @@ class CompositeValuesSourceConfig { return reverseMul; } + /** + * Returns whether this {@link ValuesSource} is used to sort the index. + */ boolean canEarlyTerminate() { return canEarlyTerminate; } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java index 0094da5069f..b7abf82a58e 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java @@ -30,6 +30,8 @@ import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.script.Script; +import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; import org.elasticsearch.search.aggregations.support.FieldContext; @@ -46,8 +48,8 @@ import java.util.Objects; import static org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder.DATE_FIELD_UNITS; /** - * A {@link CompositeValuesSourceBuilder} that that builds a {@link RoundingValuesSource} from a {@link Script} or - * a field name. + * A {@link CompositeValuesSourceBuilder} that builds a {@link RoundingValuesSource} from a {@link Script} or + * a field name using the provided interval. */ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuilder { static final String TYPE = "date_histogram"; @@ -55,6 +57,7 @@ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuild private static final ObjectParser PARSER; static { PARSER = new ObjectParser<>(DateHistogramValuesSourceBuilder.TYPE); + PARSER.declareString(DateHistogramValuesSourceBuilder::format, new ParseField("format")); PARSER.declareField((histogram, interval) -> { if (interval instanceof Long) { histogram.interval((long) interval); @@ -235,7 +238,11 @@ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuild canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(), fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField); } - return new CompositeValuesSourceConfig(name, vs, order(), canEarlyTerminate); + // dates are returned as timestamp in milliseconds-since-the-epoch unless a specific date format + // is specified in the builder. + final DocValueFormat docValueFormat = format() == null ? DocValueFormat.RAW : config.format(); + return new CompositeValuesSourceConfig(name, vs, docValueFormat, + order(), canEarlyTerminate); } else { throw new IllegalArgumentException("invalid source, expected numeric, got " + orig.getClass().getSimpleName()); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java index dd5eb1b52d0..83ada5dbbc3 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java @@ -37,7 +37,7 @@ import java.io.IOException; import java.util.Objects; /** - * A {@link CompositeValuesSourceBuilder} that that builds a {@link HistogramValuesSource} from another numeric values source + * A {@link CompositeValuesSourceBuilder} that builds a {@link HistogramValuesSource} from another numeric values source * using the provided interval. */ public class HistogramValuesSourceBuilder extends CompositeValuesSourceBuilder { @@ -128,7 +128,7 @@ public class HistogramValuesSourceBuilder extends CompositeValuesSourceBuilder buckets; private final int[] reverseMuls; private final List sourceNames; + private final List formats; - InternalComposite(String name, int size, List sourceNames, List buckets, int[] reverseMuls, + InternalComposite(String name, int size, List sourceNames, List formats, + List buckets, int[] reverseMuls, List pipelineAggregators, Map metaData) { super(name, pipelineAggregators, metaData); this.sourceNames = sourceNames; + this.formats = formats; this.buckets = buckets; this.size = size; this.reverseMuls = reverseMuls; @@ -63,14 +69,27 @@ public class InternalComposite super(in); this.size = in.readVInt(); this.sourceNames = in.readList(StreamInput::readString); + this.formats = new ArrayList<>(sourceNames.size()); + for (int i = 0; i < sourceNames.size(); i++) { + if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + formats.add(in.readNamedWriteable(DocValueFormat.class)); + } else { + formats.add(DocValueFormat.RAW); + } + } this.reverseMuls = in.readIntArray(); - this.buckets = in.readList((input) -> new InternalBucket(input, sourceNames, reverseMuls)); + this.buckets = in.readList((input) -> new InternalBucket(input, sourceNames, formats, reverseMuls)); } @Override protected void doWriteTo(StreamOutput out) throws IOException { out.writeVInt(size); out.writeStringList(sourceNames); + if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + for (DocValueFormat format : formats) { + out.writeNamedWriteable(format); + } + } out.writeIntArray(reverseMuls); out.writeList(buckets); } @@ -87,12 +106,13 @@ public class InternalComposite @Override public InternalComposite create(List buckets) { - return new InternalComposite(name, size, sourceNames, buckets, reverseMuls, pipelineAggregators(), getMetaData()); + return new InternalComposite(name, size, sourceNames, formats, buckets, reverseMuls, pipelineAggregators(), getMetaData()); } @Override public InternalBucket createBucket(InternalAggregations aggregations, InternalBucket prototype) { - return new InternalBucket(prototype.sourceNames, prototype.key, prototype.reverseMuls, prototype.docCount, aggregations); + return new InternalBucket(prototype.sourceNames, prototype.formats, prototype.key, prototype.reverseMuls, + prototype.docCount, aggregations); } public int getSize() { @@ -149,7 +169,7 @@ public class InternalComposite reduceContext.consumeBucketsAndMaybeBreak(1); result.add(reduceBucket); } - return new InternalComposite(name, size, sourceNames, result, reverseMuls, pipelineAggregators(), metaData); + return new InternalComposite(name, size, sourceNames, formats, result, reverseMuls, pipelineAggregators(), metaData); } @Override @@ -191,18 +211,21 @@ public class InternalComposite private final InternalAggregations aggregations; private final transient int[] reverseMuls; private final transient List sourceNames; + private final transient List formats; - InternalBucket(List sourceNames, CompositeKey key, int[] reverseMuls, long docCount, InternalAggregations aggregations) { + InternalBucket(List sourceNames, List formats, CompositeKey key, int[] reverseMuls, long docCount, + InternalAggregations aggregations) { this.key = key; this.docCount = docCount; this.aggregations = aggregations; this.reverseMuls = reverseMuls; this.sourceNames = sourceNames; + this.formats = formats; } @SuppressWarnings("unchecked") - InternalBucket(StreamInput in, List sourceNames, int[] reverseMuls) throws IOException { + InternalBucket(StreamInput in, List sourceNames, List formats, int[] reverseMuls) throws IOException { final Comparable[] values = new Comparable[in.readVInt()]; for (int i = 0; i < values.length; i++) { values[i] = (Comparable) in.readGenericValue(); @@ -212,6 +235,7 @@ public class InternalComposite this.aggregations = InternalAggregations.readAggregations(in); this.reverseMuls = reverseMuls; this.sourceNames = sourceNames; + this.formats = formats; } @Override @@ -242,9 +266,11 @@ public class InternalComposite @Override public Map getKey() { - return new ArrayMap(sourceNames, key.values()); + // returns the formatted key in a map + return new ArrayMap(sourceNames, formats, key.values()); } + // get the raw key (without formatting to preserve the natural order). // visible for testing CompositeKey getRawKey() { return key; @@ -260,7 +286,7 @@ public class InternalComposite } builder.append(sourceNames.get(i)); builder.append('='); - builder.append(formatObject(key.get(i))); + builder.append(formatObject(key.get(i), formats.get(i))); } builder.append('}'); return builder.toString(); @@ -284,7 +310,7 @@ public class InternalComposite aggregations.add(bucket.aggregations); } InternalAggregations aggs = InternalAggregations.reduce(aggregations, reduceContext); - return new InternalBucket(sourceNames, key, reverseMuls, docCount, aggs); + return new InternalBucket(sourceNames, formats, key, reverseMuls, docCount, aggs); } @Override @@ -303,26 +329,52 @@ public class InternalComposite @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { /** - * See {@link CompositeAggregation#bucketToXContentFragment} + * See {@link CompositeAggregation#bucketToXContent} */ throw new UnsupportedOperationException("not implemented"); } } - static Object formatObject(Object obj) { - if (obj instanceof BytesRef) { - return ((BytesRef) obj).utf8ToString(); + /** + * Format obj using the provided {@link DocValueFormat}. + * If the format is equals to {@link DocValueFormat#RAW}, the object is returned as is + * for numbers and a string for {@link BytesRef}s. + */ + static Object formatObject(Object obj, DocValueFormat format) { + if (obj.getClass() == BytesRef.class) { + BytesRef value = (BytesRef) obj; + if (format == DocValueFormat.RAW) { + return value.utf8ToString(); + } else { + return format.format((BytesRef) obj); + } + } else if (obj.getClass() == Long.class) { + Long value = (Long) obj; + if (format == DocValueFormat.RAW) { + return value; + } else { + return format.format(value); + } + } else if (obj.getClass() == Double.class) { + Double value = (Double) obj; + if (format == DocValueFormat.RAW) { + return value; + } else { + return format.format((Double) obj); + } } return obj; } private static class ArrayMap extends AbstractMap { final List keys; + final List formats; final Object[] values; - ArrayMap(List keys, Object[] values) { - assert keys.size() == values.length; + ArrayMap(List keys, List formats, Object[] values) { + assert keys.size() == values.length && keys.size() == formats.size(); this.keys = keys; + this.formats = formats; this.values = values; } @@ -335,7 +387,7 @@ public class InternalComposite public Object get(Object key) { for (int i = 0; i < keys.size(); i++) { if (key.equals(keys.get(i))) { - return formatObject(values[i]); + return formatObject(values[i], formats.get(i)); } } return null; @@ -356,7 +408,7 @@ public class InternalComposite @Override public Entry next() { SimpleEntry entry = - new SimpleEntry<>(keys.get(pos), formatObject(values[pos])); + new SimpleEntry<>(keys.get(pos), formatObject(values[pos], formats.get(pos))); ++ pos; return entry; } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java index 481c14a37f5..6ca5cdbcb62 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java @@ -95,6 +95,6 @@ public class TermsValuesSourceBuilder extends CompositeValuesSourceBuilder { } @Override public BytesRef binaryValue() { - spare.copyChars(leafScript.run().toString()); + final Object run = leafScript.run(); + CollectionUtils.ensureNoSelfReferences(run); + spare.copyChars(run.toString()); return spare.get(); } }; diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java index 41691f70c06..d7553ebf07c 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java @@ -115,7 +115,7 @@ public class CreateIndexRequestTests extends ESTestCase { final XContentType xContentType = randomFrom(XContentType.values()); BytesReference originalBytes = toShuffledXContent(createIndexRequest, xContentType, EMPTY_PARAMS, humanReadable); - CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(createIndexRequest.index()); + CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(); parsedCreateIndexRequest.source(originalBytes, xContentType); assertMappingsEqual(createIndexRequest.mappings(), parsedCreateIndexRequest.mappings()); @@ -201,7 +201,7 @@ public class CreateIndexRequestTests extends ESTestCase { return builder; } - private static void randomMappingFields(XContentBuilder builder, boolean allowObjectField) throws IOException { + public static void randomMappingFields(XContentBuilder builder, boolean allowObjectField) throws IOException { builder.startObject("properties"); int fieldsNo = randomIntBetween(0, 5); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java index 96dcef700a9..902dc187093 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java @@ -21,17 +21,26 @@ package org.elasticsearch.action.admin.indices.mapping.put; import org.elasticsearch.Version; import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequestTests; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.yaml.YamlXContent; import org.elasticsearch.index.Index; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS; + public class PutMappingRequestTests extends ESTestCase { public void testValidation() { @@ -94,4 +103,79 @@ public class PutMappingRequestTests extends ESTestCase { } } } + + public void testToXContent() throws IOException { + PutMappingRequest request = new PutMappingRequest("foo"); + request.type("my_type"); + + XContentBuilder mapping = JsonXContent.contentBuilder().startObject(); + mapping.startObject("properties"); + mapping.startObject("email"); + mapping.field("type", "text"); + mapping.endObject(); + mapping.endObject(); + mapping.endObject(); + request.source(mapping); + + String actualRequestBody = Strings.toString(request); + String expectedRequestBody = "{\"properties\":{\"email\":{\"type\":\"text\"}}}"; + assertEquals(expectedRequestBody, actualRequestBody); + } + + public void testToXContentWithEmptySource() throws IOException { + PutMappingRequest request = new PutMappingRequest("foo"); + request.type("my_type"); + + String actualRequestBody = Strings.toString(request); + String expectedRequestBody = "{}"; + assertEquals(expectedRequestBody, actualRequestBody); + } + + public void testToAndFromXContent() throws IOException { + + final PutMappingRequest putMappingRequest = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(putMappingRequest, xContentType, EMPTY_PARAMS, humanReadable); + + PutMappingRequest parsedPutMappingRequest = new PutMappingRequest(); + parsedPutMappingRequest.source(originalBytes, xContentType); + + assertMappingsEqual(putMappingRequest.source(), parsedPutMappingRequest.source()); + } + + private void assertMappingsEqual(String expected, String actual) throws IOException { + + XContentParser expectedJson = createParser(XContentType.JSON.xContent(), expected); + XContentParser actualJson = createParser(XContentType.JSON.xContent(), actual); + assertEquals(expectedJson.mapOrdered(), actualJson.mapOrdered()); + } + + /** + * Returns a random {@link PutMappingRequest}. + */ + private static PutMappingRequest createTestItem() throws IOException { + String index = randomAlphaOfLength(5); + + PutMappingRequest request = new PutMappingRequest(index); + + String type = randomAlphaOfLength(5); + request.type(type); + request.source(randomMapping()); + + return request; + } + + private static XContentBuilder randomMapping() throws IOException { + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.startObject(); + + if (randomBoolean()) { + CreateIndexRequestTests.randomMappingFields(builder, true); + } + + builder.endObject(); + return builder; + } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java new file mode 100644 index 00000000000..a52969c6281 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java @@ -0,0 +1,85 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.action.admin.indices.mapping.put; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; + +import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; + +public class PutMappingResponseTests extends ESTestCase { + + public void testToXContent() { + PutMappingResponse response = new PutMappingResponse(true); + String output = Strings.toString(response); + assertEquals("{\"acknowledged\":true}", output); + } + + public void testToAndFromXContent() throws IOException { + doFromXContentTestWithRandomFields(false); + } + + /** + * This test adds random fields and objects to the xContent rendered out to + * ensure we can parse it back to be forward compatible with additions to + * the xContent + */ + public void testFromXContentWithRandomFields() throws IOException { + doFromXContentTestWithRandomFields(true); + } + + private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException { + + final PutMappingResponse putMappingResponse = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(putMappingResponse, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); + + BytesReference mutated; + if (addRandomFields) { + mutated = insertRandomFields(xContentType, originalBytes, null, random()); + } else { + mutated = originalBytes; + } + PutMappingResponse parsedPutMappingResponse; + try (XContentParser parser = createParser(xContentType.xContent(), mutated)) { + parsedPutMappingResponse = PutMappingResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } + + assertEquals(putMappingResponse.isAcknowledged(), parsedPutMappingResponse.isAcknowledged()); + } + + /** + * Returns a random {@link PutMappingResponse}. + */ + private static PutMappingResponse createTestItem() throws IOException { + boolean acknowledged = randomBoolean(); + + return new PutMappingResponse(acknowledged); + } +} diff --git a/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java b/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java index dae421db97f..8bf074be551 100644 --- a/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java +++ b/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java @@ -570,20 +570,24 @@ public class IndexAliasesIT extends ESIntegTestCase { logger.info("--> getting alias1"); GetAliasesResponse getResponse = admin().indices().prepareGetAliases("alias1").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(5)); assertThat(getResponse.getAliases().get("foobar").size(), equalTo(1)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("alias1")); assertThat(getResponse.getAliases().get("foobar").get(0).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("test").isEmpty()); + assertTrue(getResponse.getAliases().get("test123").isEmpty()); + assertTrue(getResponse.getAliases().get("foobarbaz").isEmpty()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); AliasesExistResponse existsResponse = admin().indices().prepareAliasesExist("alias1").get(); assertThat(existsResponse.exists(), equalTo(true)); logger.info("--> getting all aliases that start with alias*"); getResponse = admin().indices().prepareGetAliases("alias*").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(5)); assertThat(getResponse.getAliases().get("foobar").size(), equalTo(2)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("alias1")); @@ -595,6 +599,10 @@ public class IndexAliasesIT extends ESIntegTestCase { assertThat(getResponse.getAliases().get("foobar").get(1).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(1).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(1).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("test").isEmpty()); + assertTrue(getResponse.getAliases().get("test123").isEmpty()); + assertTrue(getResponse.getAliases().get("foobarbaz").isEmpty()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); existsResponse = admin().indices().prepareAliasesExist("alias*").get(); assertThat(existsResponse.exists(), equalTo(true)); @@ -679,12 +687,13 @@ public class IndexAliasesIT extends ESIntegTestCase { logger.info("--> getting f* for index *bar"); getResponse = admin().indices().prepareGetAliases("f*").addIndices("*bar").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(2)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("foo")); assertThat(getResponse.getAliases().get("foobar").get(0).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); existsResponse = admin().indices().prepareAliasesExist("f*") .addIndices("*bar").get(); assertThat(existsResponse.exists(), equalTo(true)); @@ -693,13 +702,14 @@ public class IndexAliasesIT extends ESIntegTestCase { logger.info("--> getting f* for index *bac"); getResponse = admin().indices().prepareGetAliases("foo").addIndices("*bac").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(2)); assertThat(getResponse.getAliases().get("foobar").size(), equalTo(1)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("foo")); assertThat(getResponse.getAliases().get("foobar").get(0).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); existsResponse = admin().indices().prepareAliasesExist("foo") .addIndices("*bac").get(); assertThat(existsResponse.exists(), equalTo(true)); diff --git a/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java b/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java index 91a41495a46..d887387d43f 100644 --- a/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java +++ b/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java @@ -21,11 +21,14 @@ package org.elasticsearch.cluster.allocation; import org.apache.logging.log4j.Logger; import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.cluster.routing.IndexRoutingTable; import org.elasticsearch.cluster.routing.IndexShardRoutingTable; import org.elasticsearch.cluster.routing.ShardRouting; +import org.elasticsearch.cluster.routing.ShardRoutingState; import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider; import org.elasticsearch.cluster.routing.allocation.decider.ThrottlingAllocationDecider; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; @@ -34,7 +37,9 @@ import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.Scope; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static org.hamcrest.Matchers.equalTo; @@ -156,5 +161,58 @@ public class FilteringAllocationIT extends ESIntegTestCase { .execute().actionGet()); assertEquals("invalid IP address [192.168.1.1.] for [" + filterSetting.getKey() + ipKey + "]", e.getMessage()); } + + public void testTransientSettingsStillApplied() throws Exception { + List nodes = internalCluster().startNodes(6); + Set excludeNodes = new HashSet<>(nodes.subList(0, 3)); + Set includeNodes = new HashSet<>(nodes.subList(3, 6)); + logger.info("--> exclude: [{}], include: [{}]", + Strings.collectionToCommaDelimitedString(excludeNodes), + Strings.collectionToCommaDelimitedString(includeNodes)); + ensureStableCluster(6); + client().admin().indices().prepareCreate("test").get(); + ensureGreen("test"); + + Settings exclude = Settings.builder().put("cluster.routing.allocation.exclude._name", + Strings.collectionToCommaDelimitedString(excludeNodes)).build(); + + logger.info("--> updating settings"); + client().admin().cluster().prepareUpdateSettings().setTransientSettings(exclude).get(); + + logger.info("--> waiting for relocation"); + waitForRelocation(ClusterHealthStatus.GREEN); + + ClusterState state = client().admin().cluster().prepareState().get().getState(); + + for (ShardRouting shard : state.getRoutingTable().shardsWithState(ShardRoutingState.STARTED)) { + String node = state.getRoutingNodes().node(shard.currentNodeId()).node().getName(); + logger.info("--> shard on {} - {}", node, shard); + assertTrue("shard on " + node + " but should only be on the include node list: " + + Strings.collectionToCommaDelimitedString(includeNodes), + includeNodes.contains(node)); + } + + Settings other = Settings.builder().put("cluster.info.update.interval", "45s").build(); + + logger.info("--> updating settings with random persistent setting"); + client().admin().cluster().prepareUpdateSettings() + .setPersistentSettings(other).setTransientSettings(exclude).get(); + + logger.info("--> waiting for relocation"); + waitForRelocation(ClusterHealthStatus.GREEN); + + state = client().admin().cluster().prepareState().get().getState(); + + // The transient settings still exist in the state + assertThat(state.metaData().transientSettings(), equalTo(exclude)); + + for (ShardRouting shard : state.getRoutingTable().shardsWithState(ShardRoutingState.STARTED)) { + String node = state.getRoutingNodes().node(shard.currentNodeId()).node().getName(); + logger.info("--> shard on {} - {}", node, shard); + assertTrue("shard on " + node + " but should only be on the include node list: " + + Strings.collectionToCommaDelimitedString(includeNodes), + includeNodes.contains(node)); + } + } } diff --git a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java index 29c7a2b1614..0f4d0cf6634 100644 --- a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java +++ b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java @@ -261,6 +261,21 @@ public class ScopedSettingsTests extends ESTestCase { assertEquals(2, listResults.size()); assertEquals(2, intResults.size()); + service.applySettings(Settings.builder() + .put("foo.test.bar", 2) + .put("foo.test_1.bar", 7) + .putList("foo.test_list.list", "16", "17") + .putList("foo.test_list_1.list", "18", "19", "20") + .build()); + + assertEquals(2, intResults.get("test").intValue()); + assertEquals(7, intResults.get("test_1").intValue()); + assertEquals(Arrays.asList(16, 17), listResults.get("test_list")); + assertEquals(Arrays.asList(18, 19, 20), listResults.get("test_list_1")); + assertEquals(2, listResults.size()); + assertEquals(2, intResults.size()); + + listResults.clear(); intResults.clear(); @@ -286,6 +301,35 @@ public class ScopedSettingsTests extends ESTestCase { } + public void testAffixMapConsumerNotCalledWithNull() { + Setting.AffixSetting prefixSetting = Setting.prefixKeySetting("eggplant.", + (k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope)); + Setting.AffixSetting otherSetting = Setting.prefixKeySetting("other.", + (k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope)); + AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(prefixSetting, otherSetting))); + Map affixResults = new HashMap<>(); + + Consumer> consumer = (map) -> { + logger.info("--> consuming settings {}", map); + affixResults.clear(); + affixResults.putAll(map); + }; + service.addAffixMapUpdateConsumer(prefixSetting, consumer, (s, k) -> {}, randomBoolean()); + assertEquals(0, affixResults.size()); + service.applySettings(Settings.builder() + .put("eggplant._name", 2) + .build()); + assertThat(affixResults.size(), equalTo(1)); + assertThat(affixResults.get("_name"), equalTo(2)); + + service.applySettings(Settings.builder() + .put("eggplant._name", 2) + .put("other.thing", 3) + .build()); + + assertThat(affixResults.get("_name"), equalTo(2)); + } + public void testApply() { Setting testSetting = Setting.intSetting("foo.bar", 1, Property.Dynamic, Property.NodeScope); Setting testSetting2 = Setting.intSetting("foo.bar.baz", 1, Property.Dynamic, Property.NodeScope); diff --git a/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java b/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java index 8c192a2a350..2ca8189a972 100644 --- a/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java +++ b/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java @@ -25,16 +25,21 @@ import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.Counter; import org.elasticsearch.test.ESTestCase; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; +import static java.util.Collections.emptyMap; import static org.elasticsearch.common.util.CollectionUtils.eagerPartition; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -176,4 +181,15 @@ public class CollectionUtilsTests extends ESTestCase { eagerPartition(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 6) ); } + + public void testEnsureNoSelfReferences() { + CollectionUtils.ensureNoSelfReferences(emptyMap()); + CollectionUtils.ensureNoSelfReferences(null); + + Map map = new HashMap<>(); + map.put("field", map); + + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> CollectionUtils.ensureNoSelfReferences(map)); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); + } } diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java index e368163a4e9..c7205b3200f 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java @@ -35,6 +35,7 @@ import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.xcontent.XContentParser.Token; import org.elasticsearch.test.ESTestCase; import org.hamcrest.Matcher; @@ -854,19 +855,19 @@ public abstract class BaseXContentTestCase extends ESTestCase { } public void testEnsureNoSelfReferences() throws IOException { - XContentBuilder.ensureNoSelfReferences(emptyMap()); - XContentBuilder.ensureNoSelfReferences(null); + CollectionUtils.ensureNoSelfReferences(emptyMap()); + CollectionUtils.ensureNoSelfReferences(null); Map map = new HashMap<>(); map.put("field", map); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } /** * Test that the same map written multiple times do not trigger the self-reference check in - * {@link XContentBuilder#ensureNoSelfReferences(Object)} + * {@link CollectionUtils#ensureNoSelfReferences(Object)} */ public void testRepeatedMapsAndNoSelfReferences() throws Exception { Map mapB = singletonMap("b", "B"); @@ -899,7 +900,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { map1.put("map0", map0); // map 1 -> map 0 loop IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingMapsTwoLevels() throws IOException { @@ -917,7 +918,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { map2.put("map0", map0); // map 2 -> map 0 loop IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingObjectsArray() throws IOException { @@ -930,13 +931,13 @@ public abstract class BaseXContentTestCase extends ESTestCase { .startObject() .field("field", values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); e = expectThrows(IllegalArgumentException.class, () -> builder() .startObject() .array("field", values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingIterable() throws IOException { @@ -949,7 +950,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { .startObject() .field("field", (Iterable) values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingIterableOneLevel() throws IOException { @@ -964,7 +965,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { .startObject() .field("field", (Iterable) values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingIterableTwoLevels() throws IOException { @@ -984,7 +985,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { map2.put("map0", map0); // map 2 -> map 0 loop IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testChecksForDuplicates() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java index 2230436b18e..3668c7dec17 100644 --- a/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java @@ -65,13 +65,13 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase choice.equals(GEO_POINT_FIELD_NAME) || choice.equals(GEO_SHAPE_FIELD_NAME) + || choice.equals(INT_RANGE_FIELD_NAME) || choice.equals(DATE_RANGE_FIELD_NAME), () -> getRandomFieldName()); Object[] values = new Object[randomInt(5)]; for (int i = 0; i < values.length; i++) { values[i] = getRandomValueForFieldName(fieldName); diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregatorTests.java index 172aebbc0e5..0ebf957a8dd 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregatorTests.java @@ -39,6 +39,7 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.NumericUtils; import org.apache.lucene.util.TestUtil; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; @@ -68,6 +69,9 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; + public class CompositeAggregatorTests extends AggregatorTestCase { private static MappedFieldType[] FIELD_TYPES; @@ -761,6 +765,89 @@ public class CompositeAggregatorTests extends AggregatorTestCase { ); } + public void testWithDateHistogramAndFormat() throws IOException { + final List>> dataset = new ArrayList<>(); + dataset.addAll( + Arrays.asList( + createDocument("date", asLong("2017-10-20T03:08:45")), + createDocument("date", asLong("2016-09-20T09:00:34")), + createDocument("date", asLong("2016-09-20T11:34:00")), + createDocument("date", asLong("2017-10-20T06:09:24")), + createDocument("date", asLong("2017-10-19T06:09:24")), + createDocument("long", 4L) + ) + ); + final Sort sort = new Sort(new SortedNumericSortField("date", SortField.Type.LONG)); + testSearchCase(new MatchAllDocsQuery(), sort, dataset, + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)); + }, + (result) -> { + assertEquals(3, result.getBuckets().size()); + assertEquals("{date=2016-09-20}", result.getBuckets().get(0).getKeyAsString()); + assertEquals(2L, result.getBuckets().get(0).getDocCount()); + assertEquals("{date=2017-10-19}", result.getBuckets().get(1).getKeyAsString()); + assertEquals(1L, result.getBuckets().get(1).getDocCount()); + assertEquals("{date=2017-10-20}", result.getBuckets().get(2).getKeyAsString()); + assertEquals(2L, result.getBuckets().get(2).getDocCount()); + } + ); + + testSearchCase(new MatchAllDocsQuery(), sort, dataset, + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)) + .aggregateAfter(createAfterKey("date", "2016-09-20")); + + }, (result) -> { + assertEquals(2, result.getBuckets().size()); + assertEquals("{date=2017-10-19}", result.getBuckets().get(0).getKeyAsString()); + assertEquals(1L, result.getBuckets().get(0).getDocCount()); + assertEquals("{date=2017-10-20}", result.getBuckets().get(1).getKeyAsString()); + assertEquals(2L, result.getBuckets().get(1).getDocCount()); + } + ); + } + + public void testThatDateHistogramFailsFormatAfter() throws IOException { + ElasticsearchParseException exc = expectThrows(ElasticsearchParseException.class, + () -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(), + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)) + .aggregateAfter(createAfterKey("date", "now")); + }, + (result) -> {} + )); + assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class)); + assertThat(exc.getCause().getMessage(), containsString("now() is not supported in [after] key")); + + exc = expectThrows(ElasticsearchParseException.class, + () -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(), + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)) + .aggregateAfter(createAfterKey("date", "1474329600000")); + }, + (result) -> {} + )); + assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class)); + assertThat(exc.getCause().getMessage(), containsString("Parse failure")); + } + public void testWithDateHistogramAndTimeZone() throws IOException { final List>> dataset = new ArrayList<>(); dataset.addAll( diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java index 10cc5b8016d..322b70cb2d9 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java @@ -21,12 +21,15 @@ package org.elasticsearch.search.aggregations.bucket.composite; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.InternalAggregation; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.ParsedAggregation; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import org.elasticsearch.test.InternalMultiBucketAggregationTestCase; +import org.joda.time.DateTimeZone; import org.junit.After; import java.io.IOException; @@ -41,28 +44,45 @@ import java.util.TreeSet; import java.util.stream.Collectors; import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiLettersOfLengthBetween; -import static com.carrotsearch.randomizedtesting.RandomizedTest.randomLongBetween; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.lessThanOrEqualTo; public class InternalCompositeTests extends InternalMultiBucketAggregationTestCase { private List sourceNames; + private List formats; private int[] reverseMuls; - private int[] formats; + private int[] types; private int size; + private static DocValueFormat randomDocValueFormat(boolean isLong) { + if (isLong) { + // we use specific format only for date histogram on a long/date field + if (randomBoolean()) { + return new DocValueFormat.DateTime(Joda.forPattern("epoch_second"), DateTimeZone.forOffsetHours(1)); + } else { + return DocValueFormat.RAW; + } + } else { + // and the raw format for the other types + return DocValueFormat.RAW; + } + } + @Override public void setUp() throws Exception { super.setUp(); int numFields = randomIntBetween(1, 10); size = randomNumberOfBuckets(); sourceNames = new ArrayList<>(); + formats = new ArrayList<>(); reverseMuls = new int[numFields]; - formats = new int[numFields]; + types = new int[numFields]; for (int i = 0; i < numFields; i++) { sourceNames.add("field_" + i); reverseMuls[i] = randomBoolean() ? 1 : -1; - formats[i] = randomIntBetween(0, 2); + int type = randomIntBetween(0, 2); + types[i] = type; + formats.add(randomDocValueFormat(type == 0)); } } @@ -70,9 +90,10 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa @After public void tearDown() throws Exception { super.tearDown(); - sourceNames= null; - reverseMuls = null; + sourceNames = null; formats = null; + reverseMuls = null; + types = null; } @Override @@ -93,7 +114,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa private CompositeKey createCompositeKey() { Comparable[] keys = new Comparable[sourceNames.size()]; for (int j = 0; j < keys.length; j++) { - switch (formats[j]) { + switch (types[j]) { case 0: keys[j] = randomLong(); break; @@ -123,19 +144,6 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa }; } - @SuppressWarnings("unchecked") - private Comparator getBucketComparator() { - return (o1, o2) -> { - for (int i = 0; i < o1.getRawKey().size(); i++) { - int cmp = ((Comparable) o1.getRawKey().get(i)).compareTo(o2.getRawKey().get(i)) * reverseMuls[i]; - if (cmp != 0) { - return cmp; - } - } - return 0; - }; - } - @Override protected InternalComposite createTestInstance(String name, List pipelineAggregators, Map metaData, InternalAggregations aggregations) { @@ -149,11 +157,11 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa } keys.add(key); InternalComposite.InternalBucket bucket = - new InternalComposite.InternalBucket(sourceNames, key, reverseMuls, 1L, aggregations); + new InternalComposite.InternalBucket(sourceNames, formats, key, reverseMuls, 1L, aggregations); buckets.add(bucket); } Collections.sort(buckets, (o1, o2) -> o1.compareKey(o2)); - return new InternalComposite(name, size, sourceNames, buckets, reverseMuls, Collections.emptyList(), metaData); + return new InternalComposite(name, size, sourceNames, formats, buckets, reverseMuls, Collections.emptyList(), metaData); } @Override @@ -172,7 +180,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa break; case 1: buckets = new ArrayList<>(buckets); - buckets.add(new InternalComposite.InternalBucket(sourceNames, createCompositeKey(), reverseMuls, + buckets.add(new InternalComposite.InternalBucket(sourceNames, formats, createCompositeKey(), reverseMuls, randomLongBetween(1, 100), InternalAggregations.EMPTY) ); break; @@ -187,7 +195,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa default: throw new AssertionError("illegal branch"); } - return new InternalComposite(instance.getName(), instance.getSize(), sourceNames, buckets, reverseMuls, + return new InternalComposite(instance.getName(), instance.getSize(), sourceNames, formats, buckets, reverseMuls, instance.pipelineAggregators(), metaData); } diff --git a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java index 4b56d2bc9e1..c3f1da82c79 100644 --- a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java @@ -36,6 +36,7 @@ import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.MultiMatchQueryBuilder; import org.elasticsearch.index.query.Operator; import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.index.query.WrapperQueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders; @@ -1893,4 +1894,17 @@ public class SearchQueryIT extends ESIntegTestCase { } } + public void testRangeQueryRangeFields_24744() throws Exception { + assertAcked(prepareCreate("test").addMapping("type1", "int_range", "type=integer_range")); + + client().prepareIndex("test", "type1", "1") + .setSource(jsonBuilder().startObject().startObject("int_range").field("gte", 10).field("lte", 20).endObject().endObject()) + .get(); + refresh(); + + RangeQueryBuilder range = new RangeQueryBuilder("int_range").relation("intersects").from(Integer.MIN_VALUE).to(Integer.MAX_VALUE); + SearchResponse searchResponse = client().prepareSearch("test").setQuery(range).get(); + assertHitCount(searchResponse, 1); + } + } diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java index 4d30bddb3a4..f8b1572fa09 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java @@ -138,17 +138,19 @@ public abstract class AbstractQueryTestCase> public static final String STRING_FIELD_NAME = "mapped_string"; protected static final String STRING_FIELD_NAME_2 = "mapped_string_2"; protected static final String INT_FIELD_NAME = "mapped_int"; + protected static final String INT_RANGE_FIELD_NAME = "mapped_int_range"; protected static final String DOUBLE_FIELD_NAME = "mapped_double"; protected static final String BOOLEAN_FIELD_NAME = "mapped_boolean"; protected static final String DATE_FIELD_NAME = "mapped_date"; + protected static final String DATE_RANGE_FIELD_NAME = "mapped_date_range"; protected static final String OBJECT_FIELD_NAME = "mapped_object"; protected static final String GEO_POINT_FIELD_NAME = "mapped_geo_point"; protected static final String GEO_SHAPE_FIELD_NAME = "mapped_geo_shape"; - protected static final String[] MAPPED_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, - DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, OBJECT_FIELD_NAME, GEO_POINT_FIELD_NAME, + protected static final String[] MAPPED_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, INT_RANGE_FIELD_NAME, + DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, DATE_RANGE_FIELD_NAME, OBJECT_FIELD_NAME, GEO_POINT_FIELD_NAME, GEO_SHAPE_FIELD_NAME}; - private static final String[] MAPPED_LEAF_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, - DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, GEO_POINT_FIELD_NAME, }; + private static final String[] MAPPED_LEAF_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, INT_RANGE_FIELD_NAME, + DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, DATE_RANGE_FIELD_NAME, GEO_POINT_FIELD_NAME, }; private static final int NUMBER_OF_TESTQUERIES = 20; protected static Version indexVersionCreated; @@ -1077,9 +1079,11 @@ public abstract class AbstractQueryTestCase> STRING_FIELD_NAME, "type=text", STRING_FIELD_NAME_2, "type=keyword", INT_FIELD_NAME, "type=integer", + INT_RANGE_FIELD_NAME, "type=integer_range", DOUBLE_FIELD_NAME, "type=double", BOOLEAN_FIELD_NAME, "type=boolean", DATE_FIELD_NAME, "type=date", + DATE_RANGE_FIELD_NAME, "type=date_range", OBJECT_FIELD_NAME, "type=object", GEO_POINT_FIELD_NAME, "type=geo_point", GEO_SHAPE_FIELD_NAME, "type=geo_shape"