From f31fcb101ce7cbf60914a5b34a72295d266ed289 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Mon, 22 Jan 2018 11:55:54 -0700 Subject: [PATCH 01/13] Notify affixMap settings when any under the registered prefix matches (#28317) * Notify affixMap settings when any under the registered prefix matches Previously if an affixMap setting was registered, and then a completely different setting was applied, the affixMap update consumer would be notified with an empty map. This caused settings that were previously set to be unset in local state in a consumer that assumed it would only be called when the affixMap setting was changed. This commit changes the behavior so if a prefix `foo.` is registered, any setting under the prefix will have the update consumer notified if there are changes starting with `foo.`. Resolves #28316 * Add unit test * Address feedback --- .../common/settings/Setting.java | 4 +- .../allocation/FilteringAllocationIT.java | 58 +++++++++++++++++++ .../common/settings/ScopedSettingsTests.java | 44 ++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) 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 bc22dbb63ebd8..fd91a8a7601c6 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 @@ AbstractScopedSettings.SettingUpdater> newAffixMapUpdater(Consume @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 Map getValue(Settings current, Settings previous) { 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/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java b/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java index 91a41495a461a..d887387d43fe9 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 @@ 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.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 void testInvalidIPFilterClusterSettings() { .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 29c7a2b161403..0f4d0cf66346a 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 void testAddConsumerAffixMap() { 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 void testAddConsumerAffixMap() { } + 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); From 394a1dd689ed5f5a3686a5005cbc32d8593b7912 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 22 Jan 2018 13:01:13 -0800 Subject: [PATCH 02/13] Painless: Replace Painless Type with Java Class during Casts (#27847) This is the first step in a series to replace Painless Type with Java Class for any casting done during compilation. There should be no behavioural change. --- .../painless/AnalyzerCaster.java | 835 +++++++++--------- .../elasticsearch/painless/Definition.java | 119 ++- .../elasticsearch/painless/MethodWriter.java | 91 +- .../elasticsearch/painless/node/ECast.java | 3 +- .../painless/AnalyzerCasterTests.java | 8 +- .../painless/node/NodeToStringTests.java | 4 +- 6 files changed, 597 insertions(+), 463 deletions(-) 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 89f358d17e0c0..7bae2c7fcad69 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 @@ -21,6 +21,7 @@ import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Type; +import org.elasticsearch.painless.Definition.def; import java.util.Objects; @@ -36,447 +37,459 @@ public AnalyzerCaster(Definition definition) { this.definition = definition; } - public Cast getLegalCast(Location location, Type actual, Type expected, boolean explicit, boolean internal) { - Objects.requireNonNull(actual); - Objects.requireNonNull(expected); + public Cast getLegalCast(Location location, Type actualType, Type expectedType, boolean explicit, boolean internal) { + Objects.requireNonNull(actualType); + Objects.requireNonNull(expectedType); - if (actual.equals(expected)) { + Class actual = actualType.clazz; + Class expected = expectedType.clazz; + + if (actualType.dynamic) { + actual = Definition.ObjectClassTodefClass(actual); + } + + if (expectedType.dynamic) { + expected = Definition.ObjectClassTodefClass(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; + Class fsort = cast.from; + Class tsort = cast.to; if (fsort == tsort) { return constant; @@ -502,11 +515,11 @@ public Object constCast(Location location, final Object constant, final Cast cas 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() + "].")); } } 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 7729c5319ea81..52f0c2c63302d 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.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 Method getFunctionalMethod() { } 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,92 @@ public static boolean isConstantType(Type constant) { 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(); + } + public RuntimeClass getRuntimeClass(Class clazz) { return runtimeMap.get(clazz); } 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 b0c15abbfb0d5..7925856656e15 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 void writeLoopCounter(int slot, int count, Location location) { 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 void box(org.objectweb.asm.Type type) { 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 int writeNewStrings() { } } - 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 void writeToStrings() { } /** 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 void writeDynamicBinaryInstruction(Location location, Type returnType, Ty } /** 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/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index 5c2a149876139..42ec197c7f5f3 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 @@ void write(MethodWriter writer, Globals globals) { @Override public String toString() { - return singleLineToString(cast.to, child); + return singleLineToString(Definition.ClassToName(cast.to), child); } } 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 919b0881c0794..b8fe248601764 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 @@ -39,8 +39,8 @@ private static void assertCast(Type actual, Type expected, boolean mustBeExplici } Cast cast = definition.caster.getLegalCast(location, actual, expected, true, false); - assertEquals(actual, cast.from); - assertEquals(expected, cast.to); + assertEquals(actual.clazz, cast.from); + assertEquals(expected.clazz, cast.to); if (mustBeExplicit) { ClassCastException error = expectThrows(ClassCastException.class, @@ -48,8 +48,8 @@ private static void assertCast(Type actual, Type expected, boolean mustBeExplici assertTrue(error.getMessage().startsWith("Cannot cast")); } else { cast = definition.caster.getLegalCast(location, actual, expected, false, false); - assertEquals(actual, cast.from); - assertEquals(expected, cast.to); + assertEquals(actual.clazz, cast.from); + assertEquals(expected.clazz, cast.to); } } 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 424b0c286ecff..fb1a004e3cd40 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 void testECapturingFunctionRef() { 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()); } From 02a92875d9bd2bf0ab81c2865569551d7f628c50 Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Tue, 23 Jan 2018 09:06:02 +0100 Subject: [PATCH 03/13] Revert change that does not return all indices if a specific alias is requested via get alias api. (#28294) Reopens #27763 --- .../cluster/metadata/MetaData.java | 5 +---- .../elasticsearch/aliases/IndexAliasesIT.java | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) 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 98afe41c59697..23ed28569d28d 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 ImmutableOpenMap> findAliases(final String[] 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/test/java/org/elasticsearch/aliases/IndexAliasesIT.java b/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java index dae421db97f31..8bf074be551b1 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 void testIndicesGetAliases() throws Exception { 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 void testIndicesGetAliases() throws Exception { 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 void testIndicesGetAliases() throws Exception { 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 void testIndicesGetAliases() throws Exception { 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)); From 0cb48cfc113d2958dde48f52fb11a4ee84cee730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Tue, 23 Jan 2018 13:08:54 +0100 Subject: [PATCH 04/13] [Test] Re-Add integer_range and date_range field types for query builder tests (#28171) The tests for those field types were removed in #26549 because the range mapper was moved to a module, but later this mapper was moved back to core in #27854. This change adds back those two field types like before to the general setup in AbstractQueryTestCase and adds some specifics to the RangeQueryBuilder and TermsQueryBuilder tests. Also adding back an integration test in SearchQueryIT that has been removed before but that can be kept with the mapper back in core now. Relates to #28147 --- .../index/query/RangeQueryBuilderTests.java | 14 +++++++++++--- .../index/query/TermsQueryBuilderTests.java | 7 +++---- .../elasticsearch/search/query/SearchQueryIT.java | 14 ++++++++++++++ .../elasticsearch/test/AbstractQueryTestCase.java | 12 ++++++++---- 4 files changed, 36 insertions(+), 11 deletions(-) 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 2230436b18ef4..3668c7dec17a0 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 @@ protected RangeQueryBuilder doCreateTestQueryBuilder() { switch (randomIntBetween(0, 2)) { case 0: // use mapped integer field for numeric range queries - query = new RangeQueryBuilder(INT_FIELD_NAME); + query = new RangeQueryBuilder(randomBoolean() ? INT_FIELD_NAME : INT_RANGE_FIELD_NAME); query.from(randomIntBetween(1, 100)); query.to(randomIntBetween(101, 200)); break; case 1: // use mapped date field, using date string representation - query = new RangeQueryBuilder(DATE_FIELD_NAME); + query = new RangeQueryBuilder(randomBoolean() ? DATE_FIELD_NAME : DATE_RANGE_FIELD_NAME); query.from(new DateTime(System.currentTimeMillis() - randomIntBetween(0, 1000000), DateTimeZone.UTC).toString()); query.to(new DateTime(System.currentTimeMillis() + randomIntBetween(0, 1000000), DateTimeZone.UTC).toString()); // Create timestamp option only then we have a date mapper, @@ -99,6 +99,10 @@ protected RangeQueryBuilder doCreateTestQueryBuilder() { if (randomBoolean()) { query.to(null); } + if (query.fieldName().equals(INT_RANGE_FIELD_NAME) || query.fieldName().equals(DATE_RANGE_FIELD_NAME)) { + query.relation( + randomFrom(ShapeRelation.CONTAINS.toString(), ShapeRelation.INTERSECTS.toString(), ShapeRelation.WITHIN.toString())); + } return query; } @@ -143,7 +147,9 @@ protected void doAssertLuceneQuery(RangeQueryBuilder queryBuilder, Query query, } else if (getCurrentTypes().length == 0 || (queryBuilder.fieldName().equals(DATE_FIELD_NAME) == false - && queryBuilder.fieldName().equals(INT_FIELD_NAME) == false)) { + && queryBuilder.fieldName().equals(INT_FIELD_NAME) == false + && queryBuilder.fieldName().equals(DATE_RANGE_FIELD_NAME) == false + && queryBuilder.fieldName().equals(INT_RANGE_FIELD_NAME) == false)) { assertThat(query, instanceOf(TermRangeQuery.class)); TermRangeQuery termRangeQuery = (TermRangeQuery) query; assertThat(termRangeQuery.getField(), equalTo(queryBuilder.fieldName())); @@ -219,6 +225,8 @@ protected void doAssertLuceneQuery(RangeQueryBuilder queryBuilder, Query query, maxInt--; } } + } else if (queryBuilder.fieldName().equals(DATE_RANGE_FIELD_NAME) || queryBuilder.fieldName().equals(INT_RANGE_FIELD_NAME)) { + // todo can't check RangeFieldQuery because its currently package private (this will change) } else { throw new UnsupportedOperationException(); } diff --git a/server/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java index 79f9af61408b2..c945e595213fd 100644 --- a/server/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java @@ -19,12 +19,12 @@ package org.elasticsearch.index.query; -import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.PointInSetQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.util.BytesRef; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.get.GetRequest; @@ -77,9 +77,8 @@ protected TermsQueryBuilder doCreateTestQueryBuilder() { if (randomBoolean()) { // make between 0 and 5 different values of the same type String fieldName; - do { - fieldName = getRandomFieldName(); - } while (fieldName.equals(GEO_POINT_FIELD_NAME) || fieldName.equals(GEO_SHAPE_FIELD_NAME)); + fieldName = randomValueOtherThanMany(choice -> 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/query/SearchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java index 4b56d2bc9e1fe..c3f1da82c7984 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.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 void testQueryStringParserCache() throws Exception { } } + 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 ceb5160324546..0803e777de7ef 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 void onRemoval(ShardId shardId, Accountable accountable) { 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" From a6f28696d3c1920deca9eb266938c6d2add9855d Mon Sep 17 00:00:00 2001 From: Catalin Ursachi Date: Tue, 23 Jan 2018 10:03:32 +0000 Subject: [PATCH 05/13] Added Put Mapping API to high-level Rest client (#27869) Relates to #27205 --- .../elasticsearch/client/IndicesClient.java | 25 +++++ .../org/elasticsearch/client/Request.java | 21 ++++ .../elasticsearch/client/IndicesClientIT.java | 31 ++++++ .../elasticsearch/client/RequestTests.java | 34 +++++++ .../IndicesClientDocumentationIT.java | 96 +++++++++++++++++-- docs/java-rest/high-level/apis/index.asciidoc | 2 + .../high-level/apis/putmapping.asciidoc | 71 ++++++++++++++ .../high-level/supported-apis.asciidoc | 1 + .../mapping/put/PutMappingRequest.java | 13 ++- .../mapping/put/PutMappingResponse.java | 25 ++++- .../create/CreateIndexRequestTests.java | 4 +- .../mapping/put/PutMappingRequestTests.java | 84 ++++++++++++++++ .../mapping/put/PutMappingResponseTests.java | 85 ++++++++++++++++ 13 files changed, 481 insertions(+), 11 deletions(-) create mode 100644 docs/java-rest/high-level/apis/putmapping.asciidoc create mode 100644 server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java 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 2dd130fc6342e..d17f0bf94e3b7 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.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 void createAsync(CreateIndexRequest createIndexRequest, ActionListener + * 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 d16541fc04317..d84cd60409ba7 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.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; @@ -179,6 +180,22 @@ static Request createIndex(CreateIndexRequest createIndexRequest) throws IOExcep 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); } @@ -455,6 +472,10 @@ static String endpoint(String[] indices, String[] types, String endpoint) { 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 7328916599798..2445e4cd85237 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.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; @@ -109,6 +111,35 @@ public void testCreateIndex() throws IOException { } } + @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 c18fd185f40e1..76087ad914993 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.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; @@ -325,6 +326,39 @@ public void testCreateIndex() throws IOException { 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 02477ffc68231..38cd8ae540eb1 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.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 void testCreateIndex() throws IOException { // 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 void onFailure(Exception e) { } } + 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 f6da998a8476f..f7367b6e8c26d 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 0000000000000..57b8ec8964a9a --- /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 fa71b62d64e70..aede4789f4dec 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/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 eecbbc453ee4d..01a61cab7854e 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.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 @@ * @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", @@ -326,4 +327,14 @@ public void writeTo(StreamOutput out) throws IOException { out.writeBoolean(updateAllTypes); 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 64b3c77f05067..f427a316c2e81 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 @@ 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 void writeTo(StreamOutput out) throws IOException { 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/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java index c5e2aadccef99..91d3cc13599e9 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 @@ -91,7 +91,7 @@ public void testToAndFromXContent() throws IOException { 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()); @@ -177,7 +177,7 @@ private static XContentBuilder randomMapping(String type) throws IOException { 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 96dcef700a956..902dc1870934c 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 @@ 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 void testPutMappingRequestSerialization() throws IOException { } } } + + 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 0000000000000..a52969c628106 --- /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); + } +} From 9d7ab44e83f392245c591e08ba6857996fbfdc48 Mon Sep 17 00:00:00 2001 From: javanna Date: Tue, 23 Jan 2018 11:32:19 +0100 Subject: [PATCH 06/13] REST high-level client: add support for update_all_types option to put mapping API Relates to #27869 --- .../org/elasticsearch/client/Request.java | 1 + .../elasticsearch/client/RequestTests.java | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) 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 d84cd60409ba7..3eaadaefdb0f1 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 @@ -191,6 +191,7 @@ static Request putMapping(PutMappingRequest putMappingRequest) throws IOExceptio Params parameters = Params.builder(); parameters.withTimeout(putMappingRequest.timeout()); parameters.withMasterTimeout(putMappingRequest.masterNodeTimeout()); + parameters.withUpdateAllTypes(putMappingRequest.updateAllTypes()); HttpEntity entity = createEntity(putMappingRequest, REQUEST_BODY_CONTENT_TYPE); return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); 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 76087ad914993..6dae936d8d163 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 @@ -310,14 +310,7 @@ public void testCreateIndex() throws IOException { setRandomTimeout(createIndexRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); setRandomMasterTimeout(createIndexRequest, expectedParams); setRandomWaitForActiveShards(createIndexRequest::waitForActiveShards, ActiveShardCount.DEFAULT, expectedParams); - - if (randomBoolean()) { - boolean updateAllTypes = randomBoolean(); - createIndexRequest.updateAllTypes(updateAllTypes); - if (updateAllTypes) { - expectedParams.put("update_all_types", Boolean.TRUE.toString()); - } - } + setRandomUpdateAllTypes(createIndexRequest::updateAllTypes, expectedParams); Request request = Request.createIndex(createIndexRequest); assertEquals("/" + indexName, request.getEndpoint()); @@ -343,6 +336,7 @@ public void testPutMapping() throws IOException { setRandomTimeout(putMappingRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); setRandomMasterTimeout(putMappingRequest, expectedParams); + setRandomUpdateAllTypes(putMappingRequest::updateAllTypes, expectedParams); Request request = Request.putMapping(putMappingRequest); StringJoiner endpoint = new StringJoiner("/", "/", ""); @@ -1128,6 +1122,16 @@ private static void setRandomWaitForActiveShards(Consumer sett } } + private static void setRandomUpdateAllTypes(Consumer setter, Map expectedParams) { + if (randomBoolean()) { + boolean updateAllTypes = randomBoolean(); + setter.accept(updateAllTypes); + if (updateAllTypes) { + expectedParams.put("update_all_types", Boolean.TRUE.toString()); + } + } + } + private static void setRandomRefreshPolicy(Consumer setter, Map expectedParams) { if (randomBoolean()) { WriteRequest.RefreshPolicy refreshPolicy = randomFrom(WriteRequest.RefreshPolicy.values()); From 8ece2b5e67d04144e9f0e21c5537c3e346512d5f Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Tue, 23 Jan 2018 14:50:02 +0100 Subject: [PATCH 07/13] Provide a better error message for the case when all shards failed (#28333) Today we don't specify a cause which can make debugging very very tricky. This change is best effort to supply at least one cause for the failure. --- .../action/search/AbstractSearchAsyncAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 4632ef63174a2..b9e9f1ec483d2 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 @@ public final void executeNextPhase(SearchPhase currentPhase, SearchPhase nextPha * 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() From fc13e1db6a122221e6384ff04149ef776027ea8d Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Tue, 23 Jan 2018 16:57:26 +0100 Subject: [PATCH 08/13] Ensure we protect Collections obtained from scripts from self-referencing (#28335) Self referencing maps can cause SOE if they are iterated ie. in their toString methods. This chance adds some protected to the usage of those collections. --- .../CustomReflectionObjectHandler.java | 6 +++ .../rest-api-spec/test/painless/15_update.yml | 2 +- .../rest-api-spec/test/painless/30_search.yml | 36 ++++++++++++++++++ .../common/util/CollectionUtils.java | 38 +++++++++++++++++++ .../common/xcontent/XContentBuilder.java | 36 ++---------------- .../scripted/ScriptedMetricAggregator.java | 2 + .../BucketScriptPipelineAggregator.java | 3 +- .../aggregations/support/ValuesSource.java | 5 ++- .../support/values/ScriptBytesValues.java | 2 + .../subphase/ScriptFieldsFetchSubPhase.java | 2 + .../search/sort/ScriptSortBuilder.java | 5 ++- .../common/util/CollectionUtilsTests.java | 16 ++++++++ .../common/xcontent/BaseXContentTestCase.java | 23 +++++------ 13 files changed, 128 insertions(+), 48 deletions(-) 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 eef9d7af8dd01..79319369489fd 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 @@ public Iterator iterator() { } } + @Override + public String stringify(Object object) { + CollectionUtils.ensureNoSelfReferences(object); + return super.stringify(object); + } } 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 0e319be97bf0b..20047e7d4825d 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 28679cb223fd1..b7be116b38695 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/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java b/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java index 54a49f7e4f254..08d02cdea3172 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 static int[] toArray(Collection ints) { 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 070510e13ff69..9f7603c997ea8 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.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.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 @@ private XContentBuilder values(Object[] values, boolean ensureNoSelfReferences) if (values == null) { return nullValue(); } - return value(Arrays.asList(values), ensureNoSelfReferences); } @@ -865,7 +864,7 @@ private XContentBuilder map(Map values, boolean ensureNoSelfReference // 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 @@ private XContentBuilder value(Iterable values, boolean ensureNoSelfReferences // 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 @@ static void ensureNotNull(Object value, String message) { 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/metrics/scripted/ScriptedMetricAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java index bebe9f892b6c3..04ef595690a33 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java @@ -20,6 +20,7 @@ package org.elasticsearch.search.aggregations.metrics.scripted; import org.apache.lucene.index.LeafReaderContext; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.SearchScript; @@ -77,6 +78,7 @@ public InternalAggregation buildAggregation(long owningBucketOrdinal) { Object aggregation; if (combineScript != null) { aggregation = combineScript.run(); + CollectionUtils.ensureNoSelfReferences(aggregation); } else { aggregation = params.get("_agg"); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java index 0a56ae2c1cbfa..42337fbce0f98 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java @@ -112,10 +112,11 @@ public InternalAggregation reduce(InternalAggregation aggregation, ReduceContext } else { ExecutableScript executableScript = factory.newInstance(vars); Object returned = executableScript.run(); + // no need to check for self references since only numbers are valid if (returned == null) { newBuckets.add(bucket); } else { - if (!(returned instanceof Number)) { + if ((returned instanceof Number) == false) { throw new AggregationExecutionException("series_arithmetic script for reducer [" + name() + "] must return a Number"); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java b/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java index b5a109e89cbad..6dc2758fa5c25 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java @@ -30,6 +30,7 @@ import org.apache.lucene.util.Bits; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.lucene.ScorerAware; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.index.fielddata.AbstractSortingNumericDocValues; import org.elasticsearch.index.fielddata.AtomicOrdinalsFieldData; import org.elasticsearch.index.fielddata.IndexFieldData; @@ -460,7 +461,9 @@ public boolean advanceExact(int doc) throws IOException { for (int i = 0; i < count; ++i) { final BytesRef value = bytesValues.nextValue(); script.setNextAggregationValue(value.utf8ToString()); - values[i].copyChars(script.run().toString()); + Object run = script.run(); + CollectionUtils.ensureNoSelfReferences(run); + values[i].copyChars(run.toString()); } sort(); return true; diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java b/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java index 38950325daa13..662d856603e54 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java @@ -20,6 +20,7 @@ import org.apache.lucene.search.Scorer; import org.elasticsearch.common.lucene.ScorerAware; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.index.fielddata.SortedBinaryDocValues; import org.elasticsearch.index.fielddata.SortingBinaryDocValues; import org.elasticsearch.script.SearchScript; @@ -44,6 +45,7 @@ private void set(int i, Object o) { if (o == null) { values[i].clear(); } else { + CollectionUtils.ensureNoSelfReferences(o); values[i].copyChars(o.toString()); } } diff --git a/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java b/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java index c45734108f56d..948bcc3e0b3ec 100644 --- a/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java +++ b/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java @@ -22,6 +22,7 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.ReaderUtil; import org.elasticsearch.common.document.DocumentField; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.fetch.FetchSubPhase; @@ -64,6 +65,7 @@ public void hitsExecute(SearchContext context, SearchHit[] hits) throws IOExcept final Object value; try { value = leafScripts[i].run(); + CollectionUtils.ensureNoSelfReferences(value); } catch (RuntimeException e) { if (scriptFields.get(i).ignoreException()) { continue; diff --git a/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java b/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java index 331988a183fa9..99668515de5b1 100644 --- a/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java @@ -32,6 +32,7 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ObjectParser.ValueType; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -341,7 +342,9 @@ public boolean advanceExact(int doc) throws IOException { } @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/common/util/CollectionUtilsTests.java b/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java index 8c192a2a35091..2ca8189a972fd 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.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 void testPerfectPartition() { 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 e368163a4e95c..c7205b3200f1c 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.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 void testEnsureNotNull() { } 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 void testSelfReferencingMapsOneLevel() throws IOException { 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 void testSelfReferencingMapsTwoLevels() throws IOException { 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 void testSelfReferencingObjectsArray() throws IOException { .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 void testSelfReferencingIterable() throws IOException { .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 void testSelfReferencingIterableOneLevel() throws IOException { .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 void testSelfReferencingIterableTwoLevels() throws IOException { 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 { From b79a077f0c4b686313762291d18b859a79082071 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 23 Jan 2018 12:14:23 -0500 Subject: [PATCH 09/13] Reindex: log more on rare test failure The test failure tracked by #26758 occurs when we cancel a running reindex request that has been sliced into many children. The main reindex response *looks* canceled but none of the children look canceled. This is super strange because for the main request to look canceled for any length of time one of the children has to be canceled. This change adds additional logging to the test so we have more to go on to debug this the next time it fails. --- .../index/reindex/CancelTests.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) 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 3ad48d803a437..f21fb45ed7a64 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 @@ private void testCancel(String action, AbstractBulkByScrollRequestBuilder 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 @@ private void testCancel(String action, AbstractBulkByScrollRequestBuilder // 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 @@ private void testCancel(String action, AbstractBulkByScrollRequestBuilder 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 @@ private void testCancel(String action, AbstractBulkByScrollRequestBuilder 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 From a4b428323b699460ccd67a079a938a7d4a4b4fde Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 23 Jan 2018 13:35:23 -0500 Subject: [PATCH 10/13] Reindex: Wait for deletion in test The test failure tracked by #28053 occurs because we fail to get the failure response from the reindex on the first try and on our second try the delete index API call that was supposed to trigger the failure actually deletes the index during document creation. This causes the test to fail catastrophically. This PR attempts to wait for the failure to finish before the test moves on to the second attempt. The failure doesn't reproduce locally for me so I can't be sure that this helps at all with the failure, but it certainly feels like it should help some. Here is hoping this prevents similar failures in the future. --- .../elasticsearch/index/reindex/ReindexFailureTests.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 2c4f6869399c6..5449f604ba600 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 void testResponseOnSearchFailure() throws Exception { 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(), From e0a60182b089ba894145f9fb98973a44dfd995a6 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 23 Jan 2018 12:28:37 -0700 Subject: [PATCH 11/13] Fix spelling error --- docs/reference/query-dsl/query-string-syntax.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/query-dsl/query-string-syntax.asciidoc b/docs/reference/query-dsl/query-string-syntax.asciidoc index 8a7b394b2e870..c73543c99a1d9 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: ``` { From c0ffea89c208e8c516cce6ae304706e1990b8e58 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 23 Jan 2018 12:38:31 -0800 Subject: [PATCH 12/13] Completely remove Painless Type from AnalyzerCaster in favor of Java Class. (#28329) Second part in a series of PR's to remove Painless Type in favor of Java Class. This completely removes the Painless Type dependency from AnalyzerCaster. Both casting and promotion are now based on Java Class exclusively. This also allows AnalyzerCaster to be decoupled from Definition and make cast checks be static calls again. --- .../painless/AnalyzerCaster.java | 239 ++++++++---------- .../elasticsearch/painless/Definition.java | 38 ++- .../painless/node/AExpression.java | 5 +- .../painless/node/EAssignment.java | 43 ++-- .../elasticsearch/painless/node/EBinary.java | 37 ++- .../painless/node/ECapturingFunctionRef.java | 5 +- .../elasticsearch/painless/node/EComp.java | 24 +- .../painless/node/EConditional.java | 3 +- .../elasticsearch/painless/node/EElvis.java | 4 +- .../painless/node/EFunctionRef.java | 5 +- .../elasticsearch/painless/node/ELambda.java | 5 +- .../elasticsearch/painless/node/EUnary.java | 6 +- .../painless/node/SSubEachArray.java | 11 +- .../painless/node/SSubEachIterable.java | 3 +- .../painless/AnalyzerCasterTests.java | 93 ++++--- 15 files changed, 272 insertions(+), 249 deletions(-) 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 7bae2c7fcad69..abba62de39c19 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,6 @@ 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; @@ -31,26 +30,9 @@ */ public final class AnalyzerCaster { - private Definition definition; - - public AnalyzerCaster(Definition definition) { - this.definition = definition; - } - - public Cast getLegalCast(Location location, Type actualType, Type expectedType, boolean explicit, boolean internal) { - Objects.requireNonNull(actualType); - Objects.requireNonNull(expectedType); - - Class actual = actualType.clazz; - Class expected = expectedType.clazz; - - if (actualType.dynamic) { - actual = Definition.ObjectClassTodefClass(actual); - } - - if (expectedType.dynamic) { - expected = Definition.ObjectClassTodefClass(expected); - } + public static Cast getLegalCast(Location location, Class actual, Class expected, boolean explicit, boolean internal) { + Objects.requireNonNull(actual); + Objects.requireNonNull(expected); if (actual == expected) { return null; @@ -487,7 +469,7 @@ public Cast getLegalCast(Location location, Type actualType, Type expectedType, } } - public Object constCast(Location location, final Object constant, final Cast cast) { + public static Object constCast(Location location, Object constant, Cast cast) { Class fsort = cast.from; Class tsort = cast.to; @@ -498,7 +480,7 @@ public Object constCast(Location location, final Object constant, final Cast cas } 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; @@ -523,224 +505,201 @@ public Object constCast(Location location, final Object constant, final Cast cas } } - 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; } } } @@ -750,6 +709,10 @@ public Type promoteConditional(Type from0, Type from1, Object const0, Object con // 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 52f0c2c63302d..36c072570ec14 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 @@ -591,7 +591,39 @@ public static String ClassToName(Class clazz) { return "def"; } - return clazz.getCanonicalName(); + 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) { @@ -631,8 +663,6 @@ private static String buildFieldCacheKey(String structName, String fieldName, St private final Map structsMap; private final Map simpleTypesMap; - public AnalyzerCaster caster; - public Definition(List whitelists) { structsMap = new HashMap<>(); simpleTypesMap = new HashMap<>(); @@ -814,8 +844,6 @@ public Definition(List whitelists) { 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/node/AExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java index 2ca0b265430f9..eaa13ea9a8b17 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 @@ AExpression cast(Locals locals) { // 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 873f109e72d47..45ca4601e963d 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 @@ private void analyzeCompound(Locals locals) { 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 @@ private void analyzeCompound(Locals locals) { 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 df92d72a3c0c5..55c2145acd8cd 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 @@ private void analyzeMul(Locals variables) { 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 @@ private void analyzeDiv(Locals variables) { 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 @@ private void analyzeRem(Locals variables) { 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 @@ private void analyzeAdd(Locals variables) { 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 @@ private void analyzeSub(Locals variables) { 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 @@ private void analyzeLSH(Locals variables) { 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 @@ private void analyzeRSH(Locals variables) { 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 @@ private void analyzeUSH(Locals variables) { 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 @@ private void analyzeBWAnd(Locals variables) { 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 @@ private void analyzeXor(Locals variables) { 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 @@ private void analyzeBWOr(Locals variables) { 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 564fcef8eef9f..e736b2779f932 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 @@ void analyze(Locals locals) { 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/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 020ea48cd4c1b..a7bb57a1a35a4 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 @@ private void analyzeEq(Locals variables) { 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 @@ private void analyzeEqR(Locals variables) { 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 @@ private void analyzeNE(Locals variables) { 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 @@ private void analyzeNER(Locals variables) { 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 @@ private void analyzeGTE(Locals variables) { 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 @@ private void analyzeGT(Locals variables) { 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 @@ private void analyzeLTE(Locals variables) { 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 @@ private void analyzeLT(Locals variables) { 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 571e57cad24db..30a3d0d773f23 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 @@ void analyze(Locals locals) { 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 e9816c524bf3b..6005a326fe92a 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 @@ void analyze(Locals locals) { } 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 ffbb344f29cb9..13289809e49da 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 @@ void analyze(Locals locals) { 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 07de9138e7ca4..68950f5ea2a8b 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 @@ void analyze(Locals locals) { 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 e9971b538f5af..aa81407819eb9 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 @@ void analyzeNot(Locals variables) { 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 @@ void analyzeBWNot(Locals variables) { 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 @@ void analyzerAdd(Locals variables) { 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 09c73c525bec0..a4c2eb8cd22cf 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 @@ void extractVariables(Set variables) { 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 a51a459f0f3f8..26fb4a2f8459a 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.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 @@ void analyze(Locals locals) { } } - 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 b8fe248601764..69abc3481a188 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); - assertEquals(actual.clazz, cast.from); - assertEquals(expected.clazz, cast.to); + 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); - assertEquals(actual.clazz, cast.from); - assertEquals(expected.clazz, cast.to); + 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); } } From 58008e140f3ad1e553664b1c995fb99d51ebdf49 Mon Sep 17 00:00:00 2001 From: kel Date: Wed, 24 Jan 2018 14:32:46 +0800 Subject: [PATCH 13/13] Remove redundant argument for buildConfiguration of s3 plugin (#28281) --- .../repositories/s3/InternalAwsS3Service.java | 4 +-- .../s3/AwsS3ServiceImplTests.java | 27 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) 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 58a130bcd95c2..842e65e554db5 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 @@ public synchronized AmazonS3 client(Settings repositorySettings) { 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 @@ public synchronized AmazonS3 client(Settings repositorySettings) { } // 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 f85f2eb6f322f..18c701f5fc1a6 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 @@ private void assertCredentials(Settings singleRepositorySettings, Settings setti } 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 void testAWSConfigurationWithAwsSettings() { .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 void testRepositoryMaxRetries() { 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 void testRepositoryThrottleRetries() { 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));