From 65ff26fd79d978d0fd7477468d1dc158488f29b0 Mon Sep 17 00:00:00 2001 From: "Justin R. Wilson" Date: Thu, 15 Aug 2024 15:11:13 -0500 Subject: [PATCH] Union topics are not supported in Java Problem ------- Union topics do not compile with Java. Solution -------- Add support and a extend a test for union topics in Java. --- dds/idl/dds_generator.cpp | 11 +- dds/idl/dds_generator.h | 3 + dds/idl/dds_visitor.cpp | 4 + dds/idl/marshal_generator.cpp | 30 +++++- dds/idl/ts_generator.cpp | 13 ++- java/tests/complex_idl/ComplexIDLTest.java | 113 ++++++++++++++++++++- java/tests/complex_idl/Complex_Idl.idl | 24 +++++ 7 files changed, 189 insertions(+), 9 deletions(-) diff --git a/dds/idl/dds_generator.cpp b/dds/idl/dds_generator.cpp index cad1cddcd51..00c3bc71929 100644 --- a/dds/idl/dds_generator.cpp +++ b/dds/idl/dds_generator.cpp @@ -471,8 +471,15 @@ std::string field_type_name(AST_Field* field, AST_Type* field_type) field_type = field->field_type(); } const Classification cls = classify(field_type); - const std::string name = (cls & CL_STRING) ? - string_type(cls) : scoped(deepest_named_type(field_type)->name()); + std::string name; + if (cls & CL_STRING) { + name = string_type(cls); + } else if (cls & CL_PRIMITIVE) { + size_t size = 0; + name = to_cxx_type(deepest_named_type(field_type), size); + } else { + name = scoped(deepest_named_type(field_type)->name()); + } if (field) { FieldInfo af(*field); if (af.as_base_ && af.type_->anonymous()) { diff --git a/dds/idl/dds_generator.h b/dds/idl/dds_generator.h index f44dc5cece7..4f0db18cc1d 100644 --- a/dds/idl/dds_generator.h +++ b/dds/idl/dds_generator.h @@ -583,6 +583,9 @@ inline std::string to_cxx_type(AST_Type* type, std::size_t& size) return "ACE_CDR::Double"; case AST_PredefinedType::PT_longdouble: size = 16; + if (be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11) { + return "long double"; + } return "ACE_CDR::LongDouble"; case AST_PredefinedType::PT_char: size = 1; diff --git a/dds/idl/dds_visitor.cpp b/dds/idl/dds_visitor.cpp index f98ba65ab6f..d872f7c36ce 100644 --- a/dds/idl/dds_visitor.cpp +++ b/dds/idl/dds_visitor.cpp @@ -453,6 +453,10 @@ dds_visitor::visit_union(AST_Union* node) node->repoID()); } + if (!node->imported() && be_global->java()) { + java_ts_generator::generate(node); + } + return 0; } diff --git a/dds/idl/marshal_generator.cpp b/dds/idl/marshal_generator.cpp index ce2c6b1a85c..6ed37b57104 100644 --- a/dds/idl/marshal_generator.cpp +++ b/dds/idl/marshal_generator.cpp @@ -146,6 +146,10 @@ namespace { AST_Type* type, const string& prefix, bool wrap_nested_key_only, Intro& intro, const string& stru = ""); + string initializeUnion(const std::string& indent, AST_Decl* node, const string& name, + AST_Type* type, const string& prefix, bool wrap_nested_key_only, + Intro& intro, const string& stru = ""); + const std::string construct_bound_fail = "strm.get_construction_status() == Serializer::BoundConstructionFailure"; const std::string construct_elem_fail = @@ -1721,6 +1725,16 @@ namespace { } } + string initializeUnion(const std::string& indent, AST_Decl* field, const string& /*name*/, + AST_Type* type, const string& /*prefix*/, bool /*wrap_nested_key_only*/, Intro& /*intro*/, + const string& /*stru*/) + { + return + field_type_name(dynamic_cast(field), type) + " temp;\n" + + type_to_default(indent, type, "temp", type->anonymous(), false) + + "uni.value." + field->local_name()->get_string() + "(temp);\n"; + } + std::string generate_field_stream( const std::string& indent, AST_Field* field, const std::string& prefix, const std::string& field_name, bool wrap_nested_key_only, Intro& intro) @@ -3447,7 +3461,9 @@ namespace { return true; } - void gen_union_key_serializers(AST_Union* node, FieldFilter kind) + void gen_union_key_serializers(AST_Union* node, + FieldFilter kind, + const std::vector& branches) { const string cxx = scoped(node->name()); // name as a C++ class AST_Type* const discriminator = node->disc_type(); @@ -3564,7 +3580,13 @@ namespace { be_global->impl_ << " " << scoped(discriminator->name()) << " disc;\n" - << streamAndCheck(">> " + getWrapper("disc", discriminator, WD_INPUT)) + << streamAndCheck(">> " + getWrapper("disc", discriminator, WD_INPUT)); + + // Activate the branch with a default so the union is in a good state. + generateSwitchForUnion(node, "disc", initializeUnion, branches, + discriminator, "", ">> forceStreamExp", cxx.c_str()); + + be_global->impl_ << " uni.value._d(disc);\n"; } @@ -3826,9 +3848,9 @@ bool marshal_generator::gen_union(AST_Union* node, UTL_ScopedName* name, } } - gen_union_key_serializers(node, FieldFilter_NestedKeyOnly); + gen_union_key_serializers(node, FieldFilter_NestedKeyOnly, branches); if (be_global->is_topic_type(node)) { - gen_union_key_serializers(node, FieldFilter_KeyOnly); + gen_union_key_serializers(node, FieldFilter_KeyOnly, branches); } TopicKeys keys(node); diff --git a/dds/idl/ts_generator.cpp b/dds/idl/ts_generator.cpp index 4d48cdbba21..142e83f1a2d 100644 --- a/dds/idl/ts_generator.cpp +++ b/dds/idl/ts_generator.cpp @@ -640,8 +640,8 @@ bool ts_generator::gen_union(AST_Union* node, UTL_ScopedName* name, namespace java_ts_generator { - /// called directly by dds_visitor::visit_structure() if -Wb,java - void generate(AST_Structure* node) { + template + void generate_common(T* node) { UTL_ScopedName* name = node->name(); if (!(idl_global->is_dcps_type(name) || be_global->is_topic_type(node))) { @@ -705,6 +705,15 @@ namespace java_ts_generator { "}\n\n"; } + /// called by dds_visitor::visit_structure() if -Wb,java + void generate(AST_Structure* node) { + generate_common(node); + } + + /// called by dds_visitor::visit_union() if -Wb,java + void generate(AST_Union* node) { + generate_common(node); + } } namespace face_ts_generator { diff --git a/java/tests/complex_idl/ComplexIDLTest.java b/java/tests/complex_idl/ComplexIDLTest.java index c7f68c25515..0788f04b1c6 100644 --- a/java/tests/complex_idl/ComplexIDLTest.java +++ b/java/tests/complex_idl/ComplexIDLTest.java @@ -34,6 +34,7 @@ public class ComplexIDLTest extends QuoteSupport { private static DomainParticipant participant; private static Topic topic; + private static Topic union_topic; private static Publisher publisher; private static Subscriber subscriber; @@ -50,11 +51,21 @@ protected static void setUp(String[] args) { int result = typeSupport.register_type(participant, "Complex::Data"); assert (result != RETCODE_ERROR.value); + ElectionNews_tTypeSupportImpl electionNewsTypeSupport = new ElectionNews_tTypeSupportImpl(); + + result = electionNewsTypeSupport.register_type(participant, "Complex::ElectionNews_t"); + assert (result != RETCODE_ERROR.value); + topic = participant.create_topic("Complex::Topic", "Complex::Data", TOPIC_QOS_DEFAULT.get(), null, DEFAULT_STATUS_MASK.value); assert (topic != null); + union_topic = participant.create_topic("Complex::UnionTopic", "Complex::ElectionNews_t", + TOPIC_QOS_DEFAULT.get(), null, + DEFAULT_STATUS_MASK.value); + assert (union_topic != null); + publisher = participant.create_publisher(PUBLISHER_QOS_DEFAULT.get(), null, DEFAULT_STATUS_MASK.value); assert (publisher != null); @@ -212,11 +223,111 @@ public void on_data_available(DataReader dr) { System.out.println("(Those responsible have been sacked.)"); } + protected static void testElectionNews() throws Exception { + final AtomicInteger count = new AtomicInteger(); + + final Lock lock = new ReentrantLock(); + final Condition finished = lock.newCondition(); + + publisher.create_datawriter(union_topic, DATAWRITER_QOS_DEFAULT.get(), + new DDS._DataWriterListenerLocalBase() { + public void on_liveliness_lost(DataWriter dw, LivelinessLostStatus status) {} + + public void on_offered_deadline_missed(DataWriter dw, OfferedDeadlineMissedStatus status) {} + + public void on_offered_incompatible_qos(DataWriter dw, OfferedIncompatibleQosStatus status) {} + + public void on_publication_matched(DataWriter dw, PublicationMatchedStatus status) { + try { + if (status.current_count == 0) return; + // Don't run the rest of this method if the callback is + // due to the datareader going away. + + ElectionNews_tDataWriter writer = ElectionNews_tDataWriterHelper.narrow(dw); + + count.set(1); + + ElectionNews_t data = new ElectionNews_t(); + data.status(ElectionNewsType_t.ELECTION_STATUS, new Candidate_t("A Name", 10)); + + int result = writer.write(data, HANDLE_NIL.value); + assert (result != RETCODE_ERROR.value); + + } catch (Throwable t) { + t.printStackTrace(); + } + }; + }, DEFAULT_STATUS_MASK.value + ); + + lock.lock(); + try { + subscriber.create_datareader(union_topic, DATAREADER_QOS_DEFAULT.get(), + new DDS._DataReaderListenerLocalBase() { + public void on_liveliness_changed(DataReader dr, LivelinessChangedStatus status) {} + + public void on_requested_deadline_missed(DataReader dr, RequestedDeadlineMissedStatus status) {} + + public void on_requested_incompatible_qos(DataReader dr, RequestedIncompatibleQosStatus status) {} + + public void on_sample_lost(DataReader dr, SampleLostStatus status) {} + + public void on_sample_rejected(DataReader dr, SampleRejectedStatus status) {} + + public void on_subscription_matched(DataReader dr, SubscriptionMatchedStatus status) {} + + public void on_data_available(DataReader dr) { + try { + ElectionNews_tDataReader reader = ElectionNews_tDataReaderHelper.narrow(dr); + + ElectionNews_t en = new ElectionNews_t(); + en.status(ElectionNewsType_t.ELECTION_STATUS, new Candidate_t(new String(""), 0)); + ElectionNews_tHolder dh = new ElectionNews_tHolder(en); + + SampleInfo si = new SampleInfo(); + si.source_timestamp = new Time_t(); + + int result = reader.take_next_sample(dh, new SampleInfoHolder(si)); + assert (result != RETCODE_ERROR.value); + + ElectionNews_t data = dh.value; + + if (si.valid_data) { + assert data.discriminator() == ElectionNewsType_t.ELECTION_STATUS; + assert data.status().name.equals("A Name"); + assert data.status().votes == 10; + } + + if (count.decrementAndGet() == 0) { + // Signal main thread + lock.lock(); + try { + finished.signalAll(); + } finally { + lock.unlock(); + } + } + + } catch (Throwable t) { + t.printStackTrace(); + } + } + }, DEFAULT_STATUS_MASK.value + ); + + // Wait for DataReader + finished.await(); + + } finally { + lock.unlock(); + } + } + public static void main(String[] args) throws Exception { setUp(args); try { testQuotes(); - + testElectionNews(); } finally { tearDown(); } diff --git a/java/tests/complex_idl/Complex_Idl.idl b/java/tests/complex_idl/Complex_Idl.idl index f4129e96ee4..f735b0eb1d9 100644 --- a/java/tests/complex_idl/Complex_Idl.idl +++ b/java/tests/complex_idl/Complex_Idl.idl @@ -48,4 +48,28 @@ module Complex_Idl { @key long time; Position pos; }; + + typedef unsigned long Vote_t; + struct Candidate_t { + string name; + Vote_t votes; + }; + + struct ElectionResult_t { + Candidate_t winner; + Vote_t total_votes; + }; + + enum ElectionNewsType_t { + ELECTION_STATUS, + ELECTION_RESULT + }; + + @topic + union ElectionNews_t switch (@key ElectionNewsType_t) { + case ELECTION_STATUS: + Candidate_t status; + case ELECTION_RESULT: + ElectionResult_t result; + }; };