diff --git a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java index 9a4f6adca950c..3baa2bc50c61d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java @@ -559,6 +559,25 @@ public void testEnumMapperCannotBeTwoEnums() { oai + "internal.processors.cache.GridCacheOperation")); } + /** + * Negative test verifying an error is thrown by codegeneration tool if + * a field contains EnumSets of different enum types. + */ + @Test + public void testEnumMapperCannotBeTwoEnumSets() { + Compilation compilation = compile("TwoDifferentEnumSetsInCollectionMessage.java"); + + assertThat(compilation).failed(); + + String oai = "org.apache.ignite."; + + assertThat(compilation).hadErrorContaining(String.format("Multiple enums of different types are not supported " + + "for a single field [msgClsName=%s, field=%s, existingEnumType=%s, otherEnumType=%s]", + oai + "internal.TwoDifferentEnumSetsInCollectionMessage", "col", + oai + "transactions.TransactionIsolation", + oai + "internal.processors.cache.GridCacheOperation")); + } + /** * Positive test for custom EnumMapper implementation for enum field: codegeneration tool * generates a serializer using provided EnumMapper implementation. @@ -582,6 +601,29 @@ public void testCustomMapperEnumFieldsMessage() { .contentsAsUtf8String().isEqualTo(jsonFile("CustomMapperEnumFieldsMessage.json")); } + /** + * Positive test for custom EnumMapper implementation for EnumSet fields: codegeneration tool + * generates a serializer using provided EnumMapper implementation. + * Generated serializer compiles successfully. + */ + @Test + public void testCustomMapperEnumSetMessage() { + Compilation compilation = compile("CustomMapperEnumSetMessage.java", "TransactionIsolationEnumMapper.java"); + + assertThat(compilation).succeeded(); + + // No marshaller: enum fields need no marshalling, so its generation is skipped. + assertEquals(1, compilation.generatedSourceFiles().size()); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.CustomMapperEnumSetMessageSerializer") + .hasSourceEquivalentTo(javaFile("CustomMapperEnumSetMessageSerializer.java")); + + assertThat(compilation) + .generatedFile(CLASS_OUTPUT, WIRE_DIR + "messages/org.apache.ignite.internal.CustomMapperEnumSetMessage.json") + .contentsAsUtf8String().isEqualTo(jsonFile("CustomMapperEnumSetMessage.json")); + } + /** */ @Test public void testMarshallableMessage() { diff --git a/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessage.java b/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessage.java new file mode 100644 index 0000000000000..38e57242e25ca --- /dev/null +++ b/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessage.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.ignite.internal; + +import java.util.Collection; +import java.util.EnumSet; +import org.apache.ignite.plugin.extensions.communication.AbstractMessage; +import org.apache.ignite.transactions.TransactionIsolation; + +public class CustomMapperEnumSetMessage extends AbstractMessage { + @Order(0) + @CustomMapper("org.apache.ignite.internal.TransactionIsolationEnumMapper") + EnumSet isolationSet; + + @Order(1) + @CustomMapper("org.apache.ignite.internal.TransactionIsolationEnumMapper") + Collection> isolations; + + public short directType() { + return 0; + } +} diff --git a/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessage.json b/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessage.json new file mode 100644 index 0000000000000..39e007edf2800 --- /dev/null +++ b/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessage.json @@ -0,0 +1,7 @@ +{ + "class": "org.apache.ignite.internal.CustomMapperEnumSetMessage", + "fields": [ + {"order": 0, "type": "java.util.EnumSet", "name": "isolationSet", "annotations": ["@org.apache.ignite.internal.CustomMapper(\"org.apache.ignite.internal.TransactionIsolationEnumMapper\")"]}, + {"order": 1, "type": "java.util.Collection>", "name": "isolations", "annotations": ["@org.apache.ignite.internal.CustomMapper(\"org.apache.ignite.internal.TransactionIsolationEnumMapper\")"]} + ] +} diff --git a/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessageSerializer.java b/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessageSerializer.java new file mode 100644 index 0000000000000..581bf86060236 --- /dev/null +++ b/modules/core/src/test/resources/codegen/CustomMapperEnumSetMessageSerializer.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.ignite.internal; + +import java.util.List; +import org.apache.ignite.internal.CustomMapperEnumSetMessage; +import org.apache.ignite.internal.MessageSerializationContext; +import org.apache.ignite.internal.TransactionIsolationEnumMapper; +import org.apache.ignite.plugin.extensions.communication.AbstractMessage; +import org.apache.ignite.plugin.extensions.communication.CollectionImplementationType; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionType; +import org.apache.ignite.plugin.extensions.communication.MessageEnumType; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; +import org.apache.ignite.plugin.extensions.communication.RawField; +import org.apache.ignite.plugin.extensions.communication.mappers.EnumMapper; +import org.apache.ignite.transactions.TransactionIsolation; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public final class CustomMapperEnumSetMessageSerializer implements MessageSerializer { + /** */ + private static final EnumMapper transactionIsolationMapper = new TransactionIsolationEnumMapper(); + /** */ + private static final MessageCollectionType isolationSetCollDesc = new MessageCollectionType(new MessageEnumType<>(TransactionIsolation.class, transactionIsolationMapper::encode, transactionIsolationMapper::decode), CollectionImplementationType.ENUM_SET); + /** */ + private static final MessageCollectionType isolationsCollDesc = new MessageCollectionType(new MessageCollectionType(new MessageEnumType<>(TransactionIsolation.class, transactionIsolationMapper::encode, transactionIsolationMapper::decode), CollectionImplementationType.ENUM_SET), CollectionImplementationType.ARRAY_LIST); + + /** */ + @Override public final boolean writeTo(CustomMapperEnumSetMessage msg, MessageWriter writer, MessageSerializationContext ctx) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeCollection(msg.isolationSet, isolationSetCollDesc, ctx)) + return false; + + writer.incrementState(); + + case 1: + if (!writer.writeCollection(msg.isolations, isolationsCollDesc, ctx)) + return false; + + writer.incrementState(); + + case 2: + if (ctx.includeRawFields()) { + if (!writer.writeRawFields(msg.rawFields())) + return false; + } + + writer.incrementState(); + } + + return true; + } + + /** */ + @Override public final boolean readFrom(CustomMapperEnumSetMessage msg, MessageReader reader, MessageSerializationContext ctx) { + switch (reader.state()) { + case 0: + msg.isolationSet = reader.readCollection(isolationSetCollDesc, ctx); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 1: + msg.isolations = reader.readCollection(isolationsCollDesc, ctx); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 2: + if (ctx.includeRawFields()) { + List rawFields = reader.readRawFields(); + + if (!reader.isLastRead()) + return false; + + if (!rawFields.isEmpty()) + msg.rawFields(rawFields); + } + + reader.incrementState(); + } + + return true; + } + + /** {@inheritDoc} */ + @Override public final CustomMapperEnumSetMessage createMessage() { + return new CustomMapperEnumSetMessage(); + } +} diff --git a/modules/core/src/test/resources/codegen/TwoDifferentEnumSetsInCollectionMessage.java b/modules/core/src/test/resources/codegen/TwoDifferentEnumSetsInCollectionMessage.java new file mode 100644 index 0000000000000..9925ddb22c002 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TwoDifferentEnumSetsInCollectionMessage.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.apache.ignite.internal; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.Map; +import org.apache.ignite.internal.processors.cache.GridCacheOperation; +import org.apache.ignite.plugin.extensions.communication.AbstractMessage; +import org.apache.ignite.transactions.TransactionIsolation; + +public class TwoDifferentEnumSetsInCollectionMessage extends AbstractMessage { + @Order(0) + private Collection, EnumSet>> col; + + @Override + public short directType() { + return 0; + } +}