diff options
author | Mark Spruiell <mes@zeroc.com> | 2016-08-23 17:28:35 -0700 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2016-08-23 17:28:35 -0700 |
commit | e6cbf802f2977d06854a65036a860740e24d3151 (patch) | |
tree | 7e1a19dff8bb864a86da6699d0360c3d703e71c5 /cpp/src | |
parent | Small .gitignore cleanup (diff) | |
download | ice-e6cbf802f2977d06854a65036a860740e24d3151.tar.bz2 ice-e6cbf802f2977d06854a65036a860740e24d3151.tar.xz ice-e6cbf802f2977d06854a65036a860740e24d3151.zip |
Major changes in Java:
- Moved existing Java mapping sources to java-compat subdirectory
- Added new "Java 8" mapping in java subdirectory
- Significant features of Java 8 mapping:
- All classes in com.zeroc package (e.g., com.zeroc.Ice.Communicator)
- New AMI mapping that uses java.util.concurrent.CompletableFuture
- New AMD mapping that uses java.util.concurrent.CompletionStage
- New mapping for out parameters - "holder" types have been eliminated
- New mapping for optional types that uses JDK classes from java.util
(e.g., java.util.Optional)
- "TIE" classes are no longer supported or necessary; servant classes
now only need to implement a generated interface
- Moved IceGrid GUI to new mapping
- The "Java Compat" mapping is provided only for backward compatibility
to ease migration to Ice 3.7. The Slice compiler supports a new --compat
option to generate code for this mapping. However, users are encouraged
to migrate to the new mapping as soon as possible.
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/Slice/JavaUtil.cpp | 3068 | ||||
-rw-r--r-- | cpp/src/Slice/JavaUtil.h | 191 | ||||
-rw-r--r-- | cpp/src/Slice/Parser.cpp | 188 | ||||
-rw-r--r-- | cpp/src/Slice/Parser.h | 4 | ||||
-rw-r--r-- | cpp/src/Slice/Preprocessor.cpp | 29 | ||||
-rw-r--r-- | cpp/src/Slice/Preprocessor.h | 4 | ||||
-rw-r--r-- | cpp/src/slice2java/Gen.cpp | 5150 | ||||
-rw-r--r-- | cpp/src/slice2java/Gen.h | 163 | ||||
-rw-r--r-- | cpp/src/slice2java/GenCompat.cpp | 6664 | ||||
-rw-r--r-- | cpp/src/slice2java/GenCompat.h | 317 | ||||
-rw-r--r-- | cpp/src/slice2java/Main.cpp | 104 |
11 files changed, 11958 insertions, 3924 deletions
diff --git a/cpp/src/Slice/JavaUtil.cpp b/cpp/src/Slice/JavaUtil.cpp index c4e4061ea39..52c72714619 100644 --- a/cpp/src/Slice/JavaUtil.cpp +++ b/cpp/src/Slice/JavaUtil.cpp @@ -71,6 +71,438 @@ typeToBufferString(const TypePtr& type) return builtinBufferTable[builtin->kind()]; } } + +string +lookupKwd(const string& name) +{ + // + // Keyword list. *Must* be kept in alphabetical order. Note that checkedCast and uncheckedCast + // are not Java keywords, but are in this list to prevent illegal code being generated if + // someone defines Slice operations with that name. + // + // NOTE: Any changes made to this list must also be made in BasicStream.java. + // + static const string keywordList[] = + { + "abstract", "assert", "boolean", "break", "byte", "case", "catch", + "char", "checkedCast", "class", "clone", "const", "continue", "default", "do", + "double", "else", "enum", "equals", "extends", "false", "final", "finalize", + "finally", "float", "for", "getClass", "goto", "hashCode", "if", + "implements", "import", "instanceof", "int", "interface", "long", + "native", "new", "notify", "notifyAll", "null", "package", "private", + "protected", "public", "return", "short", "static", "strictfp", "super", "switch", + "synchronized", "this", "throw", "throws", "toString", "transient", + "true", "try", "uncheckedCast", "void", "volatile", "wait", "while" + }; + bool found = binary_search(&keywordList[0], + &keywordList[sizeof(keywordList) / sizeof(*keywordList)], + name); + return found ? "_" + name : name; +} + +// +// Split a scoped name into its components and return the components as a list of (unscoped) identifiers. +// +static StringList +splitScopedName(const string& scoped) +{ + assert(scoped[0] == ':'); + StringList ids; + string::size_type next = 0; + string::size_type pos; + while((pos = scoped.find("::", next)) != string::npos) + { + pos += 2; + if(pos != scoped.size()) + { + string::size_type endpos = scoped.find("::", pos); + if(endpos != string::npos) + { + ids.push_back(scoped.substr(pos, endpos - pos)); + } + } + next = pos; + } + if(next != scoped.size()) + { + ids.push_back(scoped.substr(next)); + } + else + { + ids.push_back(""); + } + + return ids; +} + +class MetaDataVisitor : public ParserVisitor +{ +public: + + virtual bool visitUnitStart(const UnitPtr& p) + { + static const string prefix = "java:"; + + // + // Validate global metadata in the top-level file and all included files. + // + StringList files = p->allFiles(); + + for(StringList::iterator q = files.begin(); q != files.end(); ++q) + { + string file = *q; + DefinitionContextPtr dc = p->findDefinitionContext(file); + assert(dc); + StringList globalMetaData = dc->getMetaData(); + for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end(); ++r) + { + string s = *r; + if(_history.count(s) == 0) + { + if(s.find(prefix) == 0) + { + bool ok = false; + + static const string packagePrefix = "java:package:"; + if(s.find(packagePrefix) == 0 && s.size() > packagePrefix.size()) + { + ok = true; + } + + if(!ok) + { + emitWarning(file, "", "ignoring invalid global metadata `" + s + "'"); + } + } + _history.insert(s); + } + } + } + return true; + } + + virtual bool visitModuleStart(const ModulePtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + return true; + } + + virtual void visitClassDecl(const ClassDeclPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + } + + virtual bool visitClassDefStart(const ClassDefPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + return true; + } + + virtual bool visitExceptionStart(const ExceptionPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + return true; + } + + virtual bool visitStructStart(const StructPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + return true; + } + + virtual void visitOperation(const OperationPtr& p) + { + if(p->hasMetaData("UserException")) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container()); + if(!cl->isLocal()) + { + ostringstream os; + os << "ignoring invalid metadata `UserException': directive applies only to local operations " + << "but enclosing " << (cl->isInterface() ? "interface" : "class") << " `" << cl->name() + << "' is not local"; + emitWarning(p->file(), p->line(), os.str()); + } + } + StringList metaData = getMetaData(p); + TypePtr returnType = p->returnType(); + if(!metaData.empty()) + { + if(!returnType) + { + for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q) + { + if(q->find("java:type:", 0) == 0) + { + emitWarning(p->file(), p->line(), "ignoring invalid metadata `" + *q + + "' for operation with void return type"); + break; + } + } + } + else + { + validateType(returnType, metaData, p->file(), p->line()); + } + } + + ParamDeclList params = p->parameters(); + for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q) + { + metaData = getMetaData(*q); + validateType((*q)->type(), metaData, p->file(), (*q)->line()); + } + + validateGetSet(p, metaData, p->file(), p->line()); + } + + virtual void visitDataMember(const DataMemberPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p->type(), metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + } + + virtual void visitSequence(const SequencePtr& p) + { + static const string protobuf = "java:protobuf:"; + static const string serializable = "java:serializable:"; + static const string bytebuffer = "java:buffer"; + StringList metaData = getMetaData(p); + const string file = p->file(); + const string line = p->line(); + for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ) + { + string s = *q++; + if(_history.count(s) == 0) // Don't complain about the same metadata more than once. + { + if(s.find(protobuf) == 0 || s.find(serializable) == 0) + { + // + // Remove from list so validateType does not try to handle as well. + // + metaData.remove(s); + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); + if(!builtin || builtin->kind() != Builtin::KindByte) + { + _history.insert(s); + emitWarning(file, line, "ignoring invalid metadata `" + s + "': " + + "this metadata can only be used with a byte sequence"); + } + } + else if(s.find(bytebuffer) == 0) + { + metaData.remove(s); + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); + if(!builtin || + (builtin->kind() != Builtin::KindByte && builtin->kind() != Builtin::KindShort && + builtin->kind() != Builtin::KindInt && builtin->kind() != Builtin::KindLong && + builtin->kind() != Builtin::KindFloat && builtin->kind() != Builtin::KindDouble)) + { + _history.insert(s); + emitWarning(file, line, "ignoring invalid metadata `" + s + "': " + + "this metadata can not be used with this type"); + } + } + } + } + + validateType(p, metaData, file, line); + validateGetSet(p, metaData, file, line); + } + + virtual void visitDictionary(const DictionaryPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + } + + virtual void visitEnum(const EnumPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + } + + virtual void visitConst(const ConstPtr& p) + { + StringList metaData = getMetaData(p); + validateType(p, metaData, p->file(), p->line()); + validateGetSet(p, metaData, p->file(), p->line()); + } + +private: + + StringList getMetaData(const ContainedPtr& cont) + { + static const string prefix = "java:"; + + StringList metaData = cont->getMetaData(); + StringList result; + + for(StringList::const_iterator p = metaData.begin(); p != metaData.end(); ++p) + { + string s = *p; + if(_history.count(s) == 0) // Don't complain about the same metadata more than once. + { + if(s.find(prefix) == 0) + { + string::size_type pos = s.find(':', prefix.size()); + if(pos == string::npos) + { + if(s.size() > prefix.size()) + { + string rest = s.substr(prefix.size()); + if(rest == "getset") + { + result.push_back(s); + } + else if(rest == "buffer") + { + result.push_back(s); + } + continue; + } + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "type") + { + result.push_back(s); + continue; + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "serializable") + { + result.push_back(s); + continue; + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "protobuf") + { + result.push_back(s); + continue; + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "serialVersionUID") + { + result.push_back(s); + continue; + } + + emitWarning(cont->file(), cont->line(), "ignoring invalid metadata `" + s + "'"); + } + else if(s == "delegate") + { + result.push_back(s); + continue; + } + + _history.insert(s); + } + } + + return result; + } + + void validateType(const SyntaxTreeBasePtr& p, const StringList& metaData, const string& file, const string& line) + { + for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); ++i) + { + // + // Type metadata ("java:type:Foo") is only supported by sequences and dictionaries. + // + if(i->find("java:type:", 0) == 0 && (!SequencePtr::dynamicCast(p) && !DictionaryPtr::dynamicCast(p))) + { + string str; + ContainedPtr cont = ContainedPtr::dynamicCast(p); + if(cont) + { + str = cont->kindOf(); + } + else + { + BuiltinPtr b = BuiltinPtr::dynamicCast(p); + assert(b); + str = b->typeId(); + } + emitWarning(file, line, "invalid metadata for " + str); + } + else if(i->find("java:buffer") == 0) + { + SequencePtr seq = SequencePtr::dynamicCast(p); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + continue; + } + + } + emitWarning(file, line, "ignoring invalid metadata `" + *i + "'"); + } + else if(i->find("java:protobuf:") == 0 || i->find("java:serializable:") == 0) + { + // + // Only valid in sequence defintion which is checked in visitSequence + // + emitWarning(file, line, "ignoring invalid metadata `" + *i + "'"); + } + else if(i->find("delegate") == 0) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(p); + if(cl && cl->isDelegate()) + { + continue; + } + emitWarning(file, line, "ignoring invalid metadata `" + *i + "'"); + } + } + } + + void validateGetSet(const SyntaxTreeBasePtr& p, const StringList& metaData, const string& file, const string& line) + { + for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); ++i) + { + // + // The "getset" metadata can only be specified on a class, struct, exception or data member. + // + if((*i) == "java:getset" && + (!ClassDefPtr::dynamicCast(p) && !StructPtr::dynamicCast(p) && !ExceptionPtr::dynamicCast(p) && + !DataMemberPtr::dynamicCast(p))) + { + string str; + ContainedPtr cont = ContainedPtr::dynamicCast(p); + if(cont) + { + str = cont->kindOf(); + } + else + { + BuiltinPtr b = BuiltinPtr::dynamicCast(p); + assert(b); + str = b->typeId(); + } + emitWarning(file, line, "invalid metadata for " + str); + } + } + } + + StringSet _history; +}; + } long @@ -162,8 +594,6 @@ Slice::computeSerialVersionUUID(const ExceptionPtr& p) return hashCode; } - - Slice::JavaOutput::JavaOutput() { } @@ -302,15 +732,15 @@ Slice::JavaOutput::printHeader() print("//\n"); } -const string Slice::JavaGenerator::_getSetMetaData = "java:getset"; +const string Slice::JavaCompatGenerator::_getSetMetaData = "java:getset"; -Slice::JavaGenerator::JavaGenerator(const string& dir) : +Slice::JavaCompatGenerator::JavaCompatGenerator(const string& dir) : _dir(dir), _out(0) { } -Slice::JavaGenerator::~JavaGenerator() +Slice::JavaCompatGenerator::~JavaCompatGenerator() { // If open throws an exception other generators could be left open // during the stack unwind. @@ -322,7 +752,7 @@ Slice::JavaGenerator::~JavaGenerator() } void -Slice::JavaGenerator::open(const string& absolute, const string& file) +Slice::JavaCompatGenerator::open(const string& absolute, const string& file) { assert(_out == 0); @@ -340,7 +770,7 @@ Slice::JavaGenerator::open(const string& absolute, const string& file) } void -Slice::JavaGenerator::close() +Slice::JavaCompatGenerator::close() { assert(_out != 0); *_out << nl; @@ -349,75 +779,12 @@ Slice::JavaGenerator::close() } Output& -Slice::JavaGenerator::output() const +Slice::JavaCompatGenerator::output() const { assert(_out != 0); return *_out; } -static string -lookupKwd(const string& name) -{ - // - // Keyword list. *Must* be kept in alphabetical order. Note that checkedCast and uncheckedCast - // are not Java keywords, but are in this list to prevent illegal code being generated if - // someone defines Slice operations with that name. - // - // NOTE: Any changes made to this list must also be made in BasicStream.java. - // - static const string keywordList[] = - { - "abstract", "assert", "boolean", "break", "byte", "case", "catch", - "char", "checkedCast", "class", "clone", "const", "continue", "default", "do", - "double", "else", "enum", "equals", "extends", "false", "final", "finalize", - "finally", "float", "for", "getClass", "goto", "hashCode", "if", - "implements", "import", "instanceof", "int", "interface", "long", - "native", "new", "notify", "notifyAll", "null", "package", "private", - "protected", "public", "return", "short", "static", "strictfp", "super", "switch", - "synchronized", "this", "throw", "throws", "toString", "transient", - "true", "try", "uncheckedCast", "void", "volatile", "wait", "while" - }; - bool found = binary_search(&keywordList[0], - &keywordList[sizeof(keywordList) / sizeof(*keywordList)], - name); - return found ? "_" + name : name; -} - -// -// Split a scoped name into its components and return the components as a list of (unscoped) identifiers. -// -static StringList -splitScopedName(const string& scoped) -{ - assert(scoped[0] == ':'); - StringList ids; - string::size_type next = 0; - string::size_type pos; - while((pos = scoped.find("::", next)) != string::npos) - { - pos += 2; - if(pos != scoped.size()) - { - string::size_type endpos = scoped.find("::", pos); - if(endpos != string::npos) - { - ids.push_back(scoped.substr(pos, endpos - pos)); - } - } - next = pos; - } - if(next != scoped.size()) - { - ids.push_back(scoped.substr(next)); - } - else - { - ids.push_back(""); - } - - return ids; -} - // // If the passed name is a scoped name, return the identical scoped name, // but with all components that are Java keywords replaced by @@ -426,7 +793,7 @@ splitScopedName(const string& scoped) // otherwise, return the name unchanged. // string -Slice::JavaGenerator::fixKwd(const string& name) const +Slice::JavaCompatGenerator::fixKwd(const string& name) const { if(name.empty()) { @@ -447,7 +814,7 @@ Slice::JavaGenerator::fixKwd(const string& name) const } string -Slice::JavaGenerator::convertScopedName(const string& scoped, const string& prefix, const string& suffix) const +Slice::JavaCompatGenerator::convertScopedName(const string& scoped, const string& prefix, const string& suffix) const { string result; string::size_type start = 0; @@ -497,7 +864,7 @@ Slice::JavaGenerator::convertScopedName(const string& scoped, const string& pref } string -Slice::JavaGenerator::getPackagePrefix(const ContainedPtr& cont) const +Slice::JavaCompatGenerator::getPackagePrefix(const ContainedPtr& cont) const { UnitPtr unit = cont->container()->unit(); string file = cont->file(); @@ -522,7 +889,7 @@ Slice::JavaGenerator::getPackagePrefix(const ContainedPtr& cont) const } string -Slice::JavaGenerator::getPackage(const ContainedPtr& cont) const +Slice::JavaCompatGenerator::getPackage(const ContainedPtr& cont) const { string scope = convertScopedName(cont->scope()); string prefix = getPackagePrefix(cont); @@ -542,10 +909,10 @@ Slice::JavaGenerator::getPackage(const ContainedPtr& cont) const } string -Slice::JavaGenerator::getAbsolute(const ContainedPtr& cont, - const string& package, - const string& prefix, - const string& suffix) const +Slice::JavaCompatGenerator::getAbsolute(const ContainedPtr& cont, + const string& package, + const string& prefix, + const string& suffix) const { string name = cont->name(); if(prefix == "" && suffix == "") @@ -568,12 +935,12 @@ Slice::JavaGenerator::getAbsolute(const ContainedPtr& cont, } string -Slice::JavaGenerator::getStaticId(const TypePtr& type, const string& package) const +Slice::JavaCompatGenerator::getStaticId(const TypePtr& type, const string& package) const { BuiltinPtr b = BuiltinPtr::dynamicCast(type); ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); - assert((b && (b->kind() == Builtin::KindObject || b->kind() == Builtin::KindValue)) || cl); + assert((b && b->usesClasses()) || cl); if(b) { @@ -590,7 +957,7 @@ Slice::JavaGenerator::getStaticId(const TypePtr& type, const string& package) co } bool -Slice::JavaGenerator::useOptionalMapping(const OperationPtr& p) +Slice::JavaCompatGenerator::useOptionalMapping(const OperationPtr& p) { // // The "java:optional" metadata can be applied to an operation or its @@ -607,7 +974,7 @@ Slice::JavaGenerator::useOptionalMapping(const OperationPtr& p) } string -Slice::JavaGenerator::getOptionalFormat(const TypePtr& type) +Slice::JavaCompatGenerator::getOptionalFormat(const TypePtr& type) { BuiltinPtr bp = BuiltinPtr::dynamicCast(type); if(bp) @@ -692,12 +1059,12 @@ Slice::JavaGenerator::getOptionalFormat(const TypePtr& type) } string -Slice::JavaGenerator::typeToString(const TypePtr& type, - TypeMode mode, - const string& package, - const StringList& metaData, - bool formal, - bool optional) const +Slice::JavaCompatGenerator::typeToString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal, + bool optional) const { static const char* builtinTable[] = { @@ -894,11 +1261,11 @@ Slice::JavaGenerator::typeToString(const TypePtr& type, } string -Slice::JavaGenerator::typeToObjectString(const TypePtr& type, - TypeMode mode, - const string& package, - const StringList& metaData, - bool formal) const +Slice::JavaCompatGenerator::typeToObjectString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal) const { static const char* builtinTable[] = { @@ -926,18 +1293,18 @@ Slice::JavaGenerator::typeToObjectString(const TypePtr& type, } void -Slice::JavaGenerator::writeMarshalUnmarshalCode(Output& out, - const string& package, - const TypePtr& type, - OptionalMode mode, - bool optionalMapping, - int tag, - const string& param, - bool marshal, - int& iter, - bool holder, - const StringList& metaData, - const string& patchParams) +Slice::JavaCompatGenerator::writeMarshalUnmarshalCode(Output& out, + const string& package, + const TypePtr& type, + OptionalMode mode, + bool optionalMapping, + int tag, + const string& param, + bool marshal, + int& iter, + bool holder, + const StringList& metaData, + const string& patchParams) { string stream = marshal ? "__os" : "__is"; string v; @@ -1864,14 +2231,14 @@ Slice::JavaGenerator::writeMarshalUnmarshalCode(Output& out, } void -Slice::JavaGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, - const string& package, - const DictionaryPtr& dict, - const string& param, - bool marshal, - int& iter, - bool useHelper, - const StringList& metaData) +Slice::JavaCompatGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, + const string& package, + const DictionaryPtr& dict, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const StringList& metaData) { string stream = marshal ? "__os" : "__is"; string v = param; @@ -1987,7 +2354,7 @@ Slice::JavaGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, } BuiltinPtr b = BuiltinPtr::dynamicCast(type); - if(ClassDeclPtr::dynamicCast(type) || (b && (b->kind() == Builtin::KindObject || b->kind() == Builtin::KindValue))) + if(ClassDeclPtr::dynamicCast(type) || (b && b->usesClasses())) { string keyTypeStr = typeToObjectString(key, TypeModeIn, package); string valueTypeStr = typeToObjectString(value, TypeModeIn, package); @@ -2010,8 +2377,7 @@ Slice::JavaGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, } } BuiltinPtr builtin = BuiltinPtr::dynamicCast(value); - if(!(builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue)) && - !ClassDeclPtr::dynamicCast(value)) + if(!(builtin && builtin->usesClasses()) && !ClassDeclPtr::dynamicCast(value)) { out << nl << "" << v << ".put(__key, __value);"; } @@ -2020,14 +2386,14 @@ Slice::JavaGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, } void -Slice::JavaGenerator::writeSequenceMarshalUnmarshalCode(Output& out, - const string& package, - const SequencePtr& seq, - const string& param, - bool marshal, - int& iter, - bool useHelper, - const StringList& metaData) +Slice::JavaCompatGenerator::writeSequenceMarshalUnmarshalCode(Output& out, + const string& package, + const SequencePtr& seq, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const StringList& metaData) { string stream = marshal ? "__os" : "__is"; string v = param; @@ -2280,33 +2646,13 @@ Slice::JavaGenerator::writeSequenceMarshalUnmarshalCode(Output& out, { bool isObject = false; ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); - if((b && (b->kind() == Builtin::KindObject || b->kind() == Builtin::KindValue)) || cl) + if((b && b->usesClasses()) || cl) { isObject = true; } out << nl << v << " = new " << instanceType << "();"; out << nl << "final int __len" << iter << " = " << stream << ".readAndCheckSeqSize(" << type->minWireSize() << ");"; - if(isObject) - { - if(b) - { - out << nl << "final String __type" << iter << " = Ice.ObjectImpl.ice_staticId();"; - } - else - { - assert(cl); - if(cl->isInterface()) - { - out << nl << "final String __type" << iter << " = " - << getAbsolute(cl, package, "_", "Disp") << ".ice_staticId();"; - } - else - { - out << nl << "final String __type" << iter << " = " << origContentS << ".ice_staticId();"; - } - } - } out << nl << "for(int __i" << iter << " = 0; __i" << iter << " < __len" << iter << "; __i" << iter << "++)"; out << sb; @@ -2482,32 +2828,12 @@ Slice::JavaGenerator::writeSequenceMarshalUnmarshalCode(Output& out, { bool isObject = false; ClassDeclPtr cl = ClassDeclPtr::dynamicCast(origContent); - if((b && (b->kind() == Builtin::KindObject || b->kind() == Builtin::KindValue)) || cl) + if((b && b->usesClasses()) || cl) { isObject = true; } out << nl << "final int __len" << iter << " = " << stream << ".readAndCheckSeqSize(" << type->minWireSize() << ");"; - if(isObject) - { - if(b) - { - out << nl << "final String __type" << iter << " = Ice.ObjectImpl.ice_staticId();"; - } - else - { - assert(cl); - if(cl->isInterface()) - { - out << nl << "final String __type" << iter << " = " - << getAbsolute(cl, package, "_", "Disp") << ".ice_staticId();"; - } - else - { - out << nl << "final String __type" << iter << " = " << origContentS << ".ice_staticId();"; - } - } - } // // We cannot allocate an array of a generic type, such as // @@ -2574,7 +2900,7 @@ Slice::JavaGenerator::writeSequenceMarshalUnmarshalCode(Output& out, } bool -Slice::JavaGenerator::findMetaData(const string& prefix, const StringList& metaData, string& value) +Slice::JavaCompatGenerator::findMetaData(const string& prefix, const StringList& metaData, string& value) { for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q) { @@ -2589,7 +2915,7 @@ Slice::JavaGenerator::findMetaData(const string& prefix, const StringList& metaD } bool -Slice::JavaGenerator::getTypeMetaData(const StringList& metaData, string& instanceType, string& formalType) +Slice::JavaCompatGenerator::getTypeMetaData(const StringList& metaData, string& instanceType, string& formalType) { // // Extract the instance type and an optional formal type. @@ -2617,7 +2943,7 @@ Slice::JavaGenerator::getTypeMetaData(const StringList& metaData, string& instan } bool -Slice::JavaGenerator::hasTypeMetaData(const TypePtr& type, const StringList& localMetaData) +Slice::JavaCompatGenerator::hasTypeMetaData(const TypePtr& type, const StringList& localMetaData) { ContainedPtr cont = ContainedPtr::dynamicCast(type); if(cont) @@ -2672,11 +2998,11 @@ Slice::JavaGenerator::hasTypeMetaData(const TypePtr& type, const StringList& loc } bool -Slice::JavaGenerator::getDictionaryTypes(const DictionaryPtr& dict, - const string& package, - const StringList& metaData, - string& instanceType, - string& formalType) const +Slice::JavaCompatGenerator::getDictionaryTypes(const DictionaryPtr& dict, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType) const { // // Get the types of the key and value. @@ -2707,11 +3033,11 @@ Slice::JavaGenerator::getDictionaryTypes(const DictionaryPtr& dict, } bool -Slice::JavaGenerator::getSequenceTypes(const SequencePtr& seq, - const string& package, - const StringList& metaData, - string& instanceType, - string& formalType) const +Slice::JavaCompatGenerator::getSequenceTypes(const SequencePtr& seq, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType) const { BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); if(builtin) @@ -2770,7 +3096,7 @@ Slice::JavaGenerator::getSequenceTypes(const SequencePtr& seq, } bool -Slice::JavaGenerator::sequenceHasHolder(const SequencePtr& p) const +Slice::JavaCompatGenerator::sequenceHasHolder(const SequencePtr& p) const { BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); if(builtin && builtin->kind() == Builtin::KindByte) @@ -2806,331 +3132,2181 @@ Slice::JavaGenerator::sequenceHasHolder(const SequencePtr& p) const JavaOutput* -Slice::JavaGenerator::createOutput() +Slice::JavaCompatGenerator::createOutput() { return new JavaOutput; } void -Slice::JavaGenerator::validateMetaData(const UnitPtr& u) +Slice::JavaCompatGenerator::validateMetaData(const UnitPtr& u) { MetaDataVisitor visitor; u->visit(&visitor, true); } -bool -Slice::JavaGenerator::MetaDataVisitor::visitUnitStart(const UnitPtr& p) +const string Slice::JavaGenerator::_getSetMetaData = "java:getset"; + +Slice::JavaGenerator::JavaGenerator(const string& dir) : + _dir(dir), + _out(0) { - static const string prefix = "java:"; +} + +Slice::JavaGenerator::~JavaGenerator() +{ + // If open throws an exception other generators could be left open + // during the stack unwind. + if(_out != 0) + { + close(); + } + assert(_out == 0); +} + +void +Slice::JavaGenerator::open(const string& absolute, const string& file) +{ + assert(_out == 0); + + JavaOutput* out = createOutput(); + try + { + out->openClass(absolute, _dir, file); + } + catch(const FileException&) + { + delete out; + throw; + } + _out = out; +} + +void +Slice::JavaGenerator::close() +{ + assert(_out != 0); + *_out << nl; + delete _out; + _out = 0; +} + +Output& +Slice::JavaGenerator::output() const +{ + assert(_out != 0); + return *_out; +} + +// +// If the passed name is a scoped name, return the identical scoped name, +// but with all components that are Java keywords replaced by +// their "_"-prefixed version; otherwise, if the passed name is +// not scoped, but a Java keyword, return the "_"-prefixed name; +// otherwise, return the name unchanged. +// +string +Slice::JavaGenerator::fixKwd(const string& name) const +{ + if(name.empty()) + { + return name; + } + if(name[0] != ':') + { + return lookupKwd(name); + } + StringList ids = splitScopedName(name); + transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd)); + stringstream result; + for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i) + { + result << "::" + *i; + } + return result.str(); +} + +string +Slice::JavaGenerator::convertScopedName(const string& scoped, const string& prefix, const string& suffix) const +{ + string result; + string::size_type start = 0; + string fscoped = fixKwd(scoped); // - // Validate global metadata in the top-level file and all included files. + // Skip leading "::" // - StringList files = p->allFiles(); + if(fscoped[start] == ':') + { + assert(fscoped[start + 1] == ':'); + start += 2; + } - for(StringList::iterator q = files.begin(); q != files.end(); ++q) + // + // Convert all occurrences of "::" to "." + // + string::size_type pos; + do { - string file = *q; - DefinitionContextPtr dc = p->findDefinitionContext(file); - assert(dc); - StringList globalMetaData = dc->getMetaData(); - for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end(); ++r) + pos = fscoped.find(':', start); + string fix; + if(pos == string::npos) { - string s = *r; - if(_history.count(s) == 0) + string s = fscoped.substr(start); + if(!s.empty()) { - if(s.find(prefix) == 0) - { - bool ok = false; - - static const string packagePrefix = "java:package:"; - if(s.find(packagePrefix) == 0 && s.size() > packagePrefix.size()) - { - ok = true; - } - - if(!ok) - { - emitWarning(file, "", "ignoring invalid global metadata `" + s + "'"); - } - } - _history.insert(s); + fix = prefix + fixKwd(s) + suffix; } } + else + { + assert(fscoped[pos + 1] == ':'); + fix = fixKwd(fscoped.substr(start, pos - start)); + start = pos + 2; + } + + if(!result.empty() && !fix.empty()) + { + result += "."; + } + result += fix; } - return true; + while(pos != string::npos); + + return result; } -bool -Slice::JavaGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p) +string +Slice::JavaGenerator::getPackagePrefix(const ContainedPtr& cont) const { - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); - return true; + UnitPtr unit = cont->container()->unit(); + string file = cont->file(); + assert(!file.empty()); + + map<string, string>::const_iterator p = _filePackagePrefix.find(file); + if(p != _filePackagePrefix.end()) + { + return p->second; + } + + static const string prefix = "java:package:"; + DefinitionContextPtr dc = unit->findDefinitionContext(file); + assert(dc); + string q = dc->findMetaData(prefix); + if(!q.empty()) + { + q = q.substr(prefix.size()); + } + _filePackagePrefix[file] = q; + return q; } -void -Slice::JavaGenerator::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p) +string +Slice::JavaGenerator::getPackage(const ContainedPtr& cont) const { - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); + string scope = convertScopedName(cont->scope()); + string prefix = getPackagePrefix(cont); + if(!prefix.empty()) + { + if(!scope.empty()) + { + return prefix + "." + scope; + } + else + { + return prefix; + } + } + + return scope; } -bool -Slice::JavaGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p) +string +Slice::JavaGenerator::getAbsolute(const ContainedPtr& cont, + const string& package, + const string& prefix, + const string& suffix) const { - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); - return true; + string name = cont->name(); + if(prefix == "" && suffix == "") + { + name = fixKwd(name); + } + string contPkg = getPackage(cont); + if(contPkg == package) + { + return prefix + name + suffix; + } + else if(!contPkg.empty()) + { + return contPkg + "." + prefix + name + suffix; + } + else + { + return prefix + name + suffix; + } } -bool -Slice::JavaGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p) +string +Slice::JavaGenerator::getStaticId(const TypePtr& type, const string& package) const { - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); - return true; + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + + assert((b && b->usesClasses()) || cl); + + if(b && b->kind() == Builtin::KindObject) + { + return "com.zeroc.Ice.Object.ice_staticId"; + } + else if(b && b->kind() == Builtin::KindValue) + { + return "com.zeroc.Ice.Value.ice_staticId"; + } + else + { + return getAbsolute(cl, package) + ".ice_staticId"; + } } bool -Slice::JavaGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p) +Slice::JavaGenerator::useOptionalMapping(const OperationPtr& p) { - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); - return true; + // + // The "java:optional" metadata can be applied to an operation or its + // interface to force the mapping to use the Optional types. + // + // Without the tag, parameters use the normal (non-optional) mapping. + // + static const string tag = "java:optional"; + + ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container()); + assert(cl); + + return p->hasMetaData(tag) || cl->hasMetaData(tag); } -void -Slice::JavaGenerator::MetaDataVisitor::visitOperation(const OperationPtr& p) +string +Slice::JavaGenerator::getOptionalFormat(const TypePtr& type) { - if(p->hasMetaData("UserException")) + const string prefix = "com.zeroc.Ice.OptionalFormat."; + + BuiltinPtr bp = BuiltinPtr::dynamicCast(type); + if(bp) { - ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container()); - if(!cl->isLocal()) + switch(bp->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + { + return prefix + "F1"; + } + case Builtin::KindShort: + { + return prefix + "F2"; + } + case Builtin::KindInt: + case Builtin::KindFloat: + { + return prefix + "F4"; + } + case Builtin::KindLong: + case Builtin::KindDouble: + { + return prefix + "F8"; + } + case Builtin::KindString: + { + return prefix + "VSize"; + } + case Builtin::KindObject: { - ostringstream os; - os << "ignoring invalid metadata `UserException': directive applies only to local operations " - << "but enclosing " << (cl->isInterface() ? "interface" : "class") << " `" << cl->name() - << "' is not local"; - emitWarning(p->file(), p->line(), os.str()); + return prefix + "Class"; + } + case Builtin::KindObjectProxy: + { + return prefix + "FSize"; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + case Builtin::KindValue: + { + return prefix + "Class"; + } } } - StringList metaData = getMetaData(p); - TypePtr returnType = p->returnType(); - if(!metaData.empty()) + + if(EnumPtr::dynamicCast(type)) + { + return prefix + "Size"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) { - if(!returnType) + return seq->type()->isVariableLength() ? prefix + "FSize" : prefix + "VSize"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ? + prefix + "FSize" : prefix + "VSize"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + return st->isVariableLength() ? prefix + "FSize" : prefix + "VSize"; + } + + if(ProxyPtr::dynamicCast(type)) + { + return prefix + "FSize"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + assert(cl); + return prefix + "Class"; +} + +string +Slice::JavaGenerator::typeToString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal, + bool optional, + bool local) const +{ + static const char* builtinTable[] = + { + "byte", + "boolean", + "short", + "int", + "long", + "float", + "double", + "String", + "com.zeroc.Ice.Value", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + static const char* builtinLocalTable[] = + { + "byte", + "boolean", + "short", + "int", + "long", + "float", + "double", + "String", + "com.zeroc.Ice.Object", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + static const char* builtinOptionalTable[] = + { + "java.util.Optional<java.lang.Byte>", + "java.util.Optional<java.lang.Boolean>", + "java.util.Optional<java.lang.Short>", + "java.util.OptionalInt", + "java.util.OptionalLong", + "java.util.Optional<java.lang.Float>", + "java.util.OptionalDouble", + "???", + "???", + "???", + "???", + "???" + }; + + if(!type) + { + assert(mode == TypeModeReturn); + return "void"; + } + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + if(optional) { - for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q) + switch(builtin->kind()) { - if(q->find("java:type:", 0) == 0) + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + { + return builtinOptionalTable[builtin->kind()]; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: { - emitWarning(p->file(), p->line(), "ignoring invalid metadata `" + *q + - "' for operation with void return type"); break; } } } else { - validateType(returnType, metaData, p->file(), p->line()); + return local ? builtinLocalTable[builtin->kind()] : builtinTable[builtin->kind()]; + } + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + + if(optional) + { + return "java.util.Optional<" + typeToObjectString(type, mode, package, metaData, formal, local) + ">"; + } + + if(cl) + { + if(cl->isInterface() && !local) + { + return "com.zeroc.Ice.Value"; + } + else + { + return getAbsolute(cl, package); } } - ParamDeclList params = p->parameters(); - for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q) + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + if(proxy) + { + ClassDefPtr def = proxy->_class()->definition(); + assert(def); + if(def->isAbstract()) + { + return getAbsolute(proxy->_class(), package, "", "Prx"); + } + else + { + return "com.zeroc.Ice.ObjectPrx"; + } + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) { - metaData = getMetaData(*q); - validateType((*q)->type(), metaData, p->file(), (*q)->line()); + string instanceType, formalType; + getDictionaryTypes(dict, package, metaData, instanceType, formalType, local); + return formal ? formalType : instanceType; } - validateGetSet(p, metaData, p->file(), p->line()); + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + string instanceType, formalType; + getSequenceTypes(seq, package, metaData, instanceType, formalType, local); + return formal ? formalType : instanceType; + } + + ContainedPtr contained = ContainedPtr::dynamicCast(type); + if(contained) + { + if(mode == TypeModeOut) + { + return getAbsolute(contained, package, "", "Holder"); + } + else + { + return getAbsolute(contained, package); + } + } + + return "???"; } -void -Slice::JavaGenerator::MetaDataVisitor::visitDataMember(const DataMemberPtr& p) +string +Slice::JavaGenerator::typeToObjectString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal, + bool local) const { - StringList metaData = getMetaData(p); - validateType(p->type(), metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); + static const char* builtinTable[] = + { + "java.lang.Byte", + "java.lang.Boolean", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Float", + "java.lang.Double", + "java.lang.String", + "com.zeroc.Ice.Value", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + static const char* builtinLocalTable[] = + { + "java.lang.Byte", + "java.lang.Boolean", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Float", + "java.lang.Double", + "java.lang.String", + "com.zeroc.Ice.Object", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin && mode != TypeModeOut) + { + return local ? builtinLocalTable[builtin->kind()] : builtinTable[builtin->kind()]; + } + + return typeToString(type, mode, package, metaData, formal, false, local); } void -Slice::JavaGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p) +Slice::JavaGenerator::writeMarshalUnmarshalCode(Output& out, + const string& package, + const TypePtr& type, + OptionalMode mode, + bool optionalMapping, + int tag, + const string& param, + bool marshal, + int& iter, + const StringList& metaData, + const string& patchParams) { - static const string protobuf = "java:protobuf:"; - static const string serializable = "java:serializable:"; - static const string bytebuffer = "java:buffer"; - StringList metaData = getMetaData(p); - const string file = p->file(); - const string line = p->line(); - for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ) + const string stream = marshal ? "__os" : "__is"; + const bool optionalParam = mode == OptionalInParam || mode == OptionalOutParam || mode == OptionalReturnParam; + + const BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) { - string s = *q++; - if(_history.count(s) == 0) // Don't complain about the same metadata more than once. + switch(builtin->kind()) { - if(s.find(protobuf) == 0 || s.find(serializable) == 0) + case Builtin::KindByte: { - // - // Remove from list so validateType does not try to handle as well. - // - metaData.remove(s); + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeByte(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeByte(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readByte(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readByte();"; + } + } + break; + } + case Builtin::KindBool: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeBool(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeBool(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readBool(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readBool();"; + } + } + break; + } + case Builtin::KindShort: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeShort(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeShort(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readShort(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readShort();"; + } + } + break; + } + case Builtin::KindInt: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeInt(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeInt(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readInt(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readInt();"; + } + } + break; + } + case Builtin::KindLong: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeLong(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeLong(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readLong(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readLong();"; + } + } + break; + } + case Builtin::KindFloat: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeFloat(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeFloat(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readFloat(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readFloat();"; + } + } + break; + } + case Builtin::KindDouble: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeDouble(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeDouble(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readDouble(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readDouble();"; + } + } + break; + } + case Builtin::KindString: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeString(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeString(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readString(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".readString();"; + } + } + break; + } + case Builtin::KindObject: + case Builtin::KindValue: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeValue(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeValue(" << param << ");"; + } + } + else + { + assert(!patchParams.empty()); + if(optionalParam) + { + out << nl << stream << ".readValue(" << tag << ", " << patchParams << ");"; + } + else + { + out << nl << stream << ".readValue(" << patchParams << ");"; + } + } + break; + } + case Builtin::KindObjectProxy: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeProxy(" << tag << ", " << param << ");"; + } + else if(mode == OptionalMember) + { + out << nl << "int __pos = " << stream << ".startSize();"; + out << nl << stream << ".writeProxy(" << param << ");"; + out << nl << stream << ".endSize(__pos);"; + } + else + { + out << nl << stream << ".writeProxy(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readProxy(" << tag << ");"; + } + else if(mode == OptionalMember) + { + out << nl << stream << ".skip(4);"; + out << nl << param << " = " << stream << ".readProxy();"; + } + else + { + out << nl << param << " = " << stream << ".readProxy();"; + } + } + break; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + return; + } - BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); - if(!builtin || builtin->kind() != Builtin::KindByte) + ProxyPtr prx = ProxyPtr::dynamicCast(type); + if(prx) + { + string typeS = typeToString(type, TypeModeIn, package); + if(marshal) + { + if(optionalParam) + { + if(optionalMapping) { - _history.insert(s); - emitWarning(file, line, "ignoring invalid metadata `" + s + "': " + - "this metadata can only be used with a byte sequence"); + out << nl << "if(" << param << " != null && " << param << ".isPresent() && " << stream + << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << "int __pos = " << stream << ".startSize();"; + out << nl << stream << ".writeProxy(" << param << ".get());"; + out << nl << stream << ".endSize(__pos);"; + out << eb; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << "int __pos = " << stream << ".startSize();"; + out << nl << stream << ".writeProxy(" << param << ");"; + out << nl << stream << ".endSize(__pos);"; + out << eb; } } - else if(s.find(bytebuffer) == 0) + else if(mode == OptionalMember) + { + out << nl << "int __pos = " << stream << ".startSize();"; + out << nl << stream << ".writeProxy(" << param << ");"; + out << nl << stream << ".endSize(__pos);"; + } + else + { + out << nl << stream << ".writeProxy(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << stream << ".skip(4);"; + out << nl << param << " = java.util.Optional.ofNullable(" << typeS << ".uncheckedCast(" << stream + << ".readProxy()));"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << param << " = java.util.Optional.empty();"; + out << eb; + } + else if(mode == OptionalMember) + { + out << nl << stream << ".skip(4);"; + out << nl << param << " = " << typeS << ".uncheckedCast(" << stream << ".readProxy());"; + } + else { - metaData.remove(s); + out << nl << param << " = " << typeS << ".uncheckedCast(" << stream << ".readProxy());"; + } + } + return; + } - BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); - if(!builtin || - (builtin->kind() != Builtin::KindByte && builtin->kind() != Builtin::KindShort && - builtin->kind() != Builtin::KindInt && builtin->kind() != Builtin::KindLong && - builtin->kind() != Builtin::KindFloat && builtin->kind() != Builtin::KindDouble)) + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeValue(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeValue(" << param << ");"; + } + } + else + { + assert(!patchParams.empty()); + if(optionalParam) + { + out << nl << stream << ".readValue(" << tag << ", " << patchParams << ");"; + } + else + { + out << nl << stream << ".readValue(" << patchParams << ");"; + } + } + return; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + string typeS = typeToString(type, TypeModeIn, package, metaData); + if(marshal) + { + if(optionalParam || mode == OptionalMember) + { + string val; + if(optionalParam) { - _history.insert(s); - emitWarning(file, line, "ignoring invalid metadata `" + s + "': " + - "this metadata can not be used with this type"); + if(optionalMapping) + { + out << nl << "if(" << param << " != null && " << param << ".isPresent() && " << stream + << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + val = param + ".get()"; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) + << "))"; + val = param; + } + out << sb; + } + else + { + val = param; + } + + if(st->isVariableLength()) + { + out << nl << "int __pos = " << stream << ".startSize();"; + out << nl << typeS << ".write(" << stream << ", " << val << ");"; + out << nl << stream << ".endSize(__pos);"; + } + else + { + out << nl << stream << ".writeSize(" << st->minWireSize() << ");"; + out << nl << typeS << ".write(" << stream << ", " << val << ");"; + } + if(optionalParam) + { + out << eb; + } + } + else + { + out << nl << typeS << ".write(" << stream << ", " << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + + if(st->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else + { + out << nl << stream << ".skipSize();"; + } + + out << nl << param << " = java.util.Optional.of(" << typeS << ".read(" << stream + << ", null));"; + + out << eb; + out << nl << "else"; + out << sb; + out << nl << param << " = java.util.Optional.empty();"; + out << eb; + } + else if(mode == OptionalMember) + { + if(st->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else + { + out << nl << stream << ".skipSize();"; } + out << nl << param << " = " << typeS << ".read(" << stream << ", " << param << ");"; + } + else + { + out << nl << param << " = " << typeS << ".read(" << stream << ", " << param << ");"; } } + return; } - validateType(p, metaData, file, line); - validateGetSet(p, metaData, file, line); -} + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + string typeS = typeToString(type, TypeModeIn, package, metaData); + if(marshal) + { + if(optionalParam) + { + if(optionalMapping) + { + out << nl << "if(" << param << " != null && " << param << ".isPresent() && " << stream + << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ".write(" << stream << ", " << param << ".get());"; + out << eb; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ".write(" << stream << ", " << param << ");"; + out << eb; + } + } + else + { + out << nl << typeS << ".write(" << stream << ", " << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << param << " = java.util.Optional.of(" << typeS << ".read(" << stream << "));"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << param << " = java.util.Optional.empty();"; + out << eb; + } + else + { + out << nl << param << " = " << typeS << ".read(" << stream << ");"; + } + } + return; + } -void -Slice::JavaGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p) -{ - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); -} + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + if(optionalParam || mode == OptionalMember) + { + string typeS = typeToString(type, TypeModeIn, package, metaData); + TypePtr keyType = dict->keyType(); + TypePtr valueType = dict->valueType(); -void -Slice::JavaGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p) -{ - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); -} + if(marshal) + { + if(optionalParam) + { + if(optionalMapping) + { + out << nl << "if(" << param << " != null && " << param << ".isPresent() && " << stream + << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) + << "))"; + out << sb; + } + } -void -Slice::JavaGenerator::MetaDataVisitor::visitConst(const ConstPtr& p) -{ - StringList metaData = getMetaData(p); - validateType(p, metaData, p->file(), p->line()); - validateGetSet(p, metaData, p->file(), p->line()); -} + if(keyType->isVariableLength() || valueType->isVariableLength()) + { + string d = optionalParam && optionalMapping ? param + ".get()" : param; + out << nl << "int __pos = " << stream << ".startSize();"; + writeDictionaryMarshalUnmarshalCode(out, package, dict, d, marshal, iter, true, metaData); + out << nl << stream << ".endSize(__pos);"; + } + else + { + const size_t wireSize = keyType->minWireSize() + valueType->minWireSize(); + string tmpName; + if(optionalParam && optionalMapping) + { + tmpName = "__optDict"; + out << nl << "final " << typeS << ' ' << tmpName << " = " << param << ".get();"; + } + else + { + tmpName = param; + } + out << nl << "final int __optSize = " << tmpName << " == null ? 0 : " << tmpName << ".size();"; + out << nl << stream << ".writeSize(__optSize > 254 ? __optSize * " << wireSize + << " + 5 : __optSize * " << wireSize << " + 1);"; + writeDictionaryMarshalUnmarshalCode(out, package, dict, tmpName, marshal, iter, true, metaData); + } -StringList -Slice::JavaGenerator::MetaDataVisitor::getMetaData(const ContainedPtr& cont) -{ - static const string prefix = "java:"; + if(optionalParam) + { + out << eb; + } + } + else + { + string tmpName; + + if(optionalParam) + { + tmpName = "__optDict"; + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ' ' << tmpName << ';'; + } + else + { + tmpName = param; + } + + if(keyType->isVariableLength() || valueType->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else + { + out << nl << stream << ".skipSize();"; + } - StringList metaData = cont->getMetaData(); - StringList result; + writeDictionaryMarshalUnmarshalCode(out, package, dict, tmpName, marshal, iter, true, metaData); + + if(optionalParam) + { + out << nl << param << " = java.util.Optional.of(" << tmpName << ");"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << param << " = java.util.Optional.empty();"; + out << eb; + } + } + } + else + { + writeDictionaryMarshalUnmarshalCode(out, package, dict, param, marshal, iter, true, metaData); + } + return; + } - for(StringList::const_iterator p = metaData.begin(); p != metaData.end(); ++p) + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) { - string s = *p; - if(_history.count(s) == 0) // Don't complain about the same metadata more than once. + if(optionalParam || mode == OptionalMember) { - if(s.find(prefix) == 0) + string typeS = typeToString(type, TypeModeIn, package, metaData); + TypePtr elemType = seq->type(); + BuiltinPtr elemBuiltin = BuiltinPtr::dynamicCast(elemType); + + if(optionalParam && elemBuiltin && elemBuiltin->kind() != Builtin::KindObject && + elemBuiltin->kind() != Builtin::KindObjectProxy && elemBuiltin->kind() != Builtin::KindValue && + !hasTypeMetaData(seq, metaData)) { - string::size_type pos = s.find(':', prefix.size()); - if(pos == string::npos) + static const char* builtinTable[] = + { + "Byte", + "Bool", + "Short", + "Int", + "Long", + "Float", + "Double", + "String", + "???", + "???", + "???" + }; + + switch(elemBuiltin->kind()) { - if(s.size() > prefix.size()) + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + case Builtin::KindString: { - string rest = s.substr(prefix.size()); - if(rest == "getset") + string bs = builtinTable[elemBuiltin->kind()]; + + if(marshal) { - result.push_back(s); + out << nl << stream << ".write" << bs << "Seq(" << tag << ", " << param << ");"; } - else if(rest == "buffer") + else { - result.push_back(s); + out << nl << param << " = " << stream << ".read" << bs << "Seq(" << tag << ");"; } - continue; + return; + } + case Builtin::KindValue: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + assert(false); + break; } } - else if(s.substr(prefix.size(), pos - prefix.size()) == "type") + } + + string ignore; + const size_t wireSize = elemType->minWireSize(); + + if(marshal) + { + if(optionalParam) { - result.push_back(s); - continue; + if(optionalMapping) + { + out << nl << "if(" << param << " != null && " << param << ".isPresent() && " << stream + << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) + << "))"; + } + + out << sb; } - else if(s.substr(prefix.size(), pos - prefix.size()) == "serializable") + + if(elemType->isVariableLength()) { - result.push_back(s); - continue; + string s = optionalParam && optionalMapping ? param + ".get()" : param; + out << nl << "int __pos = " << stream << ".startSize();"; + writeSequenceMarshalUnmarshalCode(out, package, seq, s, marshal, iter, true, metaData); + out << nl << stream << ".endSize(__pos);"; } - else if(s.substr(prefix.size(), pos - prefix.size()) == "protobuf") + else if(findMetaData("java:type:", metaData, ignore) || + findMetaData("java:type:", seq->getMetaData(), ignore)) { - result.push_back(s); - continue; + // + // The sequence is an instance of java.util.List<E>, where E is a fixed-size type. + // If the element type is bool or byte, we do NOT write an extra size. + // + + string tmpName; + if(optionalParam && optionalMapping) + { + tmpName = "__optSeq"; + out << nl << "final " << typeS << ' ' << tmpName << " = " << param << ".get();"; + } + else + { + tmpName = param; + } + + if(wireSize > 1) + { + out << nl << "final int __optSize = " << tmpName << " == null ? 0 : " << tmpName << ".size();"; + out << nl << stream << ".writeSize(__optSize > 254 ? __optSize * " << wireSize + << " + 5 : __optSize * " << wireSize << " + 1);"; + } + writeSequenceMarshalUnmarshalCode(out, package, seq, tmpName, marshal, iter, true, metaData); } - else if(s.substr(prefix.size(), pos - prefix.size()) == "serialVersionUID") + else if(findMetaData("java:protobuf:", seq->getMetaData(), ignore) || + findMetaData("java:serializable:", seq->getMetaData(), ignore)) { - result.push_back(s); - continue; + // + // This just writes a byte sequence. + // + string s = optionalParam && optionalMapping ? param + ".get()" : param; + writeSequenceMarshalUnmarshalCode(out, package, seq, s, marshal, iter, true, metaData); } + else + { + // + // At this point we have a regular Java array of a fixed-size type. + // + + string tmpName; + if(optionalParam && optionalMapping) + { + tmpName = "__optSeq"; + out << nl << "final " << typeS << ' ' << tmpName << " = " << param << ".get();"; + } + else + { + tmpName = param; + } + + if(wireSize > 1) + { + out << nl << "final int __optSize = " << tmpName << " == null ? 0 : " << tmpName << ".length;"; + out << nl << stream << ".writeSize(__optSize > 254 ? __optSize * " << wireSize + << " + 5 : __optSize * " << wireSize << " + 1);"; + } - emitWarning(cont->file(), cont->line(), "ignoring invalid metadata `" + s + "'"); + writeSequenceMarshalUnmarshalCode(out, package, seq, tmpName, marshal, iter, true, metaData); + } + + if(optionalParam) + { + out << eb; + } } - else if(s == "delegate") + else { - result.push_back(s); - continue; + string tmpName; + if(optionalParam) + { + tmpName = "__optSeq"; + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ' ' << tmpName << ';'; + } + else + { + tmpName = param; + } + + if(elemType->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else if(wireSize > 1) + { + if(findMetaData("java:type:", metaData, ignore) || + findMetaData("java:type:", seq->getMetaData(), ignore)) + { + // + // The sequence is an instance of java.util.List<E>, where E is a fixed-size type. + // + + out << nl << stream << ".skipSize();"; + } + else if(!findMetaData("java:protobuf:", seq->getMetaData(), ignore) && + !findMetaData("java:serializable:", seq->getMetaData(), ignore)) + { + out << nl << stream << ".skipSize();"; + } + } + + writeSequenceMarshalUnmarshalCode(out, package, seq, tmpName, marshal, iter, true, metaData); + + if(optionalParam) + { + out << nl << param << " = java.util.Optional.of(" << tmpName << ");"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << param << " = java.util.Optional.empty();"; + out << eb; + } } + } + else + { + writeSequenceMarshalUnmarshalCode(out, package, seq, param, marshal, iter, true, metaData); + } + return; + } + + ConstructedPtr constructed = ConstructedPtr::dynamicCast(type); + assert(constructed); + string typeS = getAbsolute(constructed, package); + if(marshal) + { + out << nl << typeS << ".write(" << stream << ", " << param << ");"; + } + else + { + out << nl << param << " = " << typeS << ".read(" << stream << ");"; + } +} + +void +Slice::JavaGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, + const string& package, + const DictionaryPtr& dict, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const StringList& metaData) +{ + string stream = marshal ? "__os" : "__is"; + string v = param; - _history.insert(s); + string instanceType; + + // + // We have to determine whether it's possible to use the + // type's generated helper class for this marshal/unmarshal + // task. Since the user may have specified a custom type in + // metadata, it's possible that the helper class is not + // compatible and therefore we'll need to generate the code + // in-line instead. + // + // Specifically, there may be "local" metadata (i.e., from + // a data member or parameter definition) that overrides the + // original type. We'll compare the mapped types with and + // without local metadata to determine whether we can use + // the helper. + // + string formalType; + getDictionaryTypes(dict, "", metaData, instanceType, formalType, false); + string origInstanceType, origFormalType; + getDictionaryTypes(dict, "", StringList(), origInstanceType, origFormalType, false); + if((formalType != origFormalType) || (!marshal && instanceType != origInstanceType)) + { + useHelper = false; + } + + // + // If we can use the helper, it's easy. + // + if(useHelper) + { + string typeS = getAbsolute(dict, package); + if(marshal) + { + out << nl << typeS << "Helper.write(" << stream << ", " << v << ");"; + } + else + { + out << nl << v << " = " << typeS << "Helper.read(" << stream << ");"; } + return; } - return result; + TypePtr key = dict->keyType(); + TypePtr value = dict->valueType(); + + string keyS = typeToString(key, TypeModeIn, package); + string valueS = typeToString(value, TypeModeIn, package); + + ostringstream o; + o << iter; + string iterS = o.str(); + iter++; + + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << "__os.writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "__os.writeSize(" << v << ".size());"; + string keyObjectS = typeToObjectString(key, TypeModeIn, package); + string valueObjectS = typeToObjectString(value, TypeModeIn, package); + out << nl << "for(java.util.Map.Entry<" << keyObjectS << ", " << valueObjectS << "> __e : " << v + << ".entrySet())"; + out << sb; + for(int i = 0; i < 2; i++) + { + string arg; + TypePtr type; + if(i == 0) + { + arg = "__e.getKey()"; + type = key; + } + else + { + arg = "__e.getValue()"; + type = value; + } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, arg, true, iter); + } + out << eb; + out << eb; + } + else + { + out << nl << v << " = new " << instanceType << "();"; + out << nl << "int __sz" << iterS << " = __is.readSize();"; + out << nl << "for(int __i" << iterS << " = 0; __i" << iterS << " < __sz" << iterS << "; __i" << iterS << "++)"; + out << sb; + for(int i = 0; i < 2; i++) + { + string arg; + TypePtr type; + string typeS; + if(i == 0) + { + arg = "__key"; + type = key; + typeS = keyS; + } + else + { + arg = "__value"; + type = value; + typeS = valueS; + } + + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(ClassDeclPtr::dynamicCast(type) || (b && b->usesClasses())) + { + string keyTypeStr = typeToObjectString(key, TypeModeIn, package); + string valueTypeStr = typeToObjectString(value, TypeModeIn, package); + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, arg, false, iter, StringList(), + "new com.zeroc.IceInternal.DictionaryPatcher<" + keyTypeStr + ", " + + valueTypeStr + ">(" + v + ", " + typeS + ".class, " + typeS + + ".ice_staticId, __key)"); + } + else + { + if(StructPtr::dynamicCast(type)) + { + out << nl << typeS << ' ' << arg << " = null;"; + } + else + { + out << nl << typeS << ' ' << arg << ';'; + } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, arg, false, iter); + } + } + BuiltinPtr builtin = BuiltinPtr::dynamicCast(value); + if(!(builtin && builtin->usesClasses()) && !ClassDeclPtr::dynamicCast(value)) + { + out << nl << "" << v << ".put(__key, __value);"; + } + out << eb; + } } void -Slice::JavaGenerator::MetaDataVisitor::validateType(const SyntaxTreeBasePtr& p, const StringList& metaData, - const string& file, const string& line) +Slice::JavaGenerator::writeSequenceMarshalUnmarshalCode(Output& out, + const string& package, + const SequencePtr& seq, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const StringList& metaData) { - for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); ++i) + string stream = marshal ? "__os" : "__is"; + string v = param; + + // + // If the sequence is a byte sequence, check if there's the serializable or protobuf metadata to + // get rid of these two easy cases first. + // + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && builtin->kind() == Builtin::KindByte) + { + string meta; + static const string protobuf = "java:protobuf:"; + static const string serializable = "java:serializable:"; + if(seq->findMetaData(serializable, meta)) + { + if(marshal) + { + out << nl << stream << ".writeSerializable(" << v << ");"; + } + else + { + string type = typeToString(seq, TypeModeIn, package); + out << nl << v << " = (" << type << ")" << stream << ".readSerializable();"; + } + return; + } + else if(seq->findMetaData(protobuf, meta)) + { + if(marshal) + { + out << nl << "if(!" << v << ".isInitialized())"; + out << sb; + out << nl << "throw new com.zeroc.Ice.MarshalException(\"type not fully initialized\");"; + out << eb; + out << nl << stream << ".writeByteSeq(" << v << ".toByteArray());"; + } + else + { + string type = typeToString(seq, TypeModeIn, package); + out << nl << "try"; + out << sb; + out << nl << v << " = " << type << ".parseFrom(" << stream << ".readByteSeq());"; + out << eb; + out << nl << "catch(com.google.protobuf.InvalidProtocolBufferException __ex)"; + out << sb; + out << nl << "throw new com.zeroc.Ice.MarshalException(__ex);"; + out << eb; + } + return; + } + } + + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string meta; + static const string bytebuffer = "java:buffer"; + if(seq->findMetaData(bytebuffer, meta) || findMetaData(bytebuffer, metaData, meta)) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + { + if(marshal) + { + out << nl << stream << ".writeByteBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readByteBuffer();"; + } + break; + } + case Builtin::KindShort: + { + if(marshal) + { + out << nl << stream << ".writeShortBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readShortBuffer();"; + } + break; + } + case Builtin::KindInt: + { + if(marshal) + { + out << nl << stream << ".writeIntBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readIntBuffer();"; + } + break; + } + case Builtin::KindLong: + { + if(marshal) + { + out << nl << stream << ".writeLongBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readLongBuffer();"; + } + break; + } + case Builtin::KindFloat: + { + if(marshal) + { + out << nl << stream << ".writeFloatBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readFloatBuffer();"; + } + break; + } + case Builtin::KindDouble: + { + if(marshal) + { + out << nl << stream << ".writeDoubleBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readDoubleBuffer();"; + } + break; + } + case Builtin::KindBool: + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + assert(false); + break; + } + } + return; + } + } + + bool customType = false; + string instanceType; + + // + // We have to determine whether it's possible to use the + // type's generated helper class for this marshal/unmarshal + // task. Since the user may have specified a custom type in + // metadata, it's possible that the helper class is not + // compatible and therefore we'll need to generate the code + // in-line instead. + // + // Specifically, there may be "local" metadata (i.e., from + // a data member or parameter definition) that overrides the + // original type. We'll compare the mapped types with and + // without local metadata to determine whether we can use + // the helper. + // + string formalType; + customType = getSequenceTypes(seq, "", metaData, instanceType, formalType, false); + string origInstanceType, origFormalType; + getSequenceTypes(seq, "", StringList(), origInstanceType, origFormalType, false); + if((formalType != origFormalType) || (!marshal && instanceType != origInstanceType)) + { + useHelper = false; + } + + // + // If we can use the helper, it's easy. + // + if(useHelper) + { + string typeS = getAbsolute(seq, package); + if(marshal) + { + out << nl << typeS << "Helper.write(" << stream << ", " << v << ");"; + } + else + { + out << nl << v << " = " << typeS << "Helper.read(" << stream << ");"; + } + return; + } + + // + // Determine sequence depth. + // + int depth = 0; + TypePtr origContent = seq->type(); + SequencePtr s = SequencePtr::dynamicCast(origContent); + while(s) { // - // Type metadata ("java:type:Foo") is only supported by sequences and dictionaries. + // Stop if the inner sequence type has a custom, serializable or protobuf type. + // + if(hasTypeMetaData(s)) + { + break; + } + depth++; + origContent = s->type(); + s = SequencePtr::dynamicCast(origContent); + } + string origContentS = typeToString(origContent, TypeModeIn, package); + + TypePtr type = seq->type(); + + if(customType) + { + // + // Marshal/unmarshal a custom sequence type. // - if(i->find("java:type:", 0) == 0 && (!SequencePtr::dynamicCast(p) && !DictionaryPtr::dynamicCast(p))) + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + string typeS = getAbsolute(seq, package); + ostringstream o; + o << origContentS; + int d = depth; + while(d--) + { + o << "[]"; + } + string cont = o.str(); + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << stream << ".writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << stream << ".writeSize(" << v << ".size());"; + string typeS = typeToString(type, TypeModeIn, package); + out << nl << "for(" << typeS << " __elem : " << v << ')'; + out << sb; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "__elem", true, iter); + out << eb; + out << eb; // else + } + else + { + bool isObject = false; + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if((b && b->usesClasses()) || cl) + { + isObject = true; + } + out << nl << v << " = new " << instanceType << "();"; + out << nl << "final int __len" << iter << " = " << stream << ".readAndCheckSeqSize(" << type->minWireSize() + << ");"; + out << nl << "for(int __i" << iter << " = 0; __i" << iter << " < __len" << iter << "; __i" << iter + << "++)"; + out << sb; + if(isObject) + { + // + // Add a null value to the list as a placeholder for the element. + // + out << nl << v << ".add(null);"; + ostringstream patchParams; + patchParams << "new com.zeroc.IceInternal.ListPatcher<" << origContentS << ">(" << v << ", " + << origContentS << ".class, " << origContentS << ".ice_staticId, __i" << iter << ')'; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "__elem", false, iter, + StringList(), patchParams.str()); + } + else + { + if(StructPtr::dynamicCast(type)) + { + out << nl << cont << " __elem = null;"; + } + else + { + out << nl << cont << " __elem;"; + } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "__elem", false, iter); + } + if(!isObject) + { + out << nl << v << ".add(__elem);"; + } + out << eb; + iter++; + } + } + else + { + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b && b->kind() != Builtin::KindObject && + b->kind() != Builtin::KindValue && + b->kind() != Builtin::KindObjectProxy) + { + switch(b->kind()) + { + case Builtin::KindByte: + { + if(marshal) + { + out << nl << stream << ".writeByteSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readByteSeq();"; + } + break; + } + case Builtin::KindBool: + { + if(marshal) + { + out << nl << stream << ".writeBoolSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readBoolSeq();"; + } + break; + } + case Builtin::KindShort: + { + if(marshal) + { + out << nl << stream << ".writeShortSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readShortSeq();"; + } + break; + } + case Builtin::KindInt: + { + if(marshal) + { + out << nl << stream << ".writeIntSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readIntSeq();"; + } + break; + } + case Builtin::KindLong: + { + if(marshal) + { + out << nl << stream << ".writeLongSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readLongSeq();"; + } + break; + } + case Builtin::KindFloat: + { + if(marshal) + { + out << nl << stream << ".writeFloatSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readFloatSeq();"; + } + break; + } + case Builtin::KindDouble: + { + if(marshal) + { + out << nl << stream << ".writeDoubleSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readDoubleSeq();"; + } + break; + } + case Builtin::KindString: + { + if(marshal) + { + out << nl << stream << ".writeStringSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readStringSeq();"; + } + break; + } + case Builtin::KindValue: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + } + else { - string str; - ContainedPtr cont = ContainedPtr::dynamicCast(p); - if(cont) + if(marshal) { - str = cont->kindOf(); + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << stream << ".writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << stream << ".writeSize(" << v << ".length);"; + out << nl << "for(int __i" << iter << " = 0; __i" << iter << " < " << v << ".length; __i" << iter + << "++)"; + out << sb; + ostringstream o; + o << v << "[__i" << iter << "]"; + iter++; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), true, iter); + out << eb; + out << eb; } else { - BuiltinPtr b = BuiltinPtr::dynamicCast(p); - assert(b); - str = b->typeId(); + bool isObject = false; + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(origContent); + if((b && b->usesClasses()) || cl) + { + isObject = true; + } + out << nl << "final int __len" << iter << " = " << stream << ".readAndCheckSeqSize(" + << type->minWireSize() << ");"; + // + // We cannot allocate an array of a generic type, such as + // + // arr = new Map<String, String>[sz]; + // + // Attempting to compile this code results in a "generic array creation" error + // message. This problem can occur when the sequence's element type is a + // dictionary, or when the element type is a nested sequence that uses a custom + // mapping. + // + // The solution is to rewrite the code as follows: + // + // arr = (Map<String, String>[])new Map[sz]; + // + // Unfortunately, this produces an unchecked warning during compilation. + // + // A simple test is to look for a "<" character in the content type, which + // indicates the use of a generic type. + // + string::size_type pos = origContentS.find('<'); + if(pos != string::npos) + { + string nonGenericType = origContentS.substr(0, pos); + out << nl << v << " = (" << origContentS << "[]"; + int d = depth; + while(d--) + { + out << "[]"; + } + out << ")new " << nonGenericType << "[__len" << iter << "]"; + } + else + { + out << nl << v << " = new " << origContentS << "[__len" << iter << "]"; + } + int d = depth; + while(d--) + { + out << "[]"; + } + out << ';'; + out << nl << "for(int __i" << iter << " = 0; __i" << iter << " < __len" << iter << "; __i" << iter + << "++)"; + out << sb; + ostringstream o; + o << v << "[__i" << iter << "]"; + if(isObject) + { + ostringstream patchParams; + patchParams << "new com.zeroc.IceInternal.SequencePatcher<" << origContentS << ">(" << v << ", " + << origContentS << ".class, " << origContentS << ".ice_staticId, __i" << iter + << ')'; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), false, iter, + StringList(), patchParams.str()); + } + else + { + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), false, iter); + } + out << eb; + iter++; } - emitWarning(file, line, "invalid metadata for " + str); } - else if(i->find("java:buffer") == 0) + } +} + +bool +Slice::JavaGenerator::findMetaData(const string& prefix, const StringList& metaData, string& value) +{ + for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q) + { + if(q->find(prefix) == 0) { - SequencePtr seq = SequencePtr::dynamicCast(p); + value = *q; + return true; + } + } + + return false; +} + +bool +Slice::JavaGenerator::getTypeMetaData(const StringList& metaData, string& instanceType, string& formalType) +{ + // + // Extract the instance type and an optional formal type. + // The correct syntax is "java:type:instance-type[:formal-type]". + // + static const string prefix = "java:type:"; + string directive; + if(findMetaData(prefix, metaData, directive)) + { + string::size_type pos = directive.find(':', prefix.size()); + if(pos != string::npos) + { + instanceType = directive.substr(prefix.size(), pos - prefix.size()); + formalType = directive.substr(pos + 1); + } + else + { + instanceType = directive.substr(prefix.size()); + formalType.clear(); + } + return true; + } + + return false; +} + +bool +Slice::JavaGenerator::hasTypeMetaData(const TypePtr& type, const StringList& localMetaData) +{ + ContainedPtr cont = ContainedPtr::dynamicCast(type); + if(cont) + { + static const string prefix = "java:type:"; + string directive; + + if(findMetaData(prefix, localMetaData, directive)) + { + return true; + } + + StringList metaData = cont->getMetaData(); + + if(findMetaData(prefix, metaData, directive)) + { + return true; + } + + if(findMetaData("java:protobuf:", metaData, directive) || + findMetaData("java:serializable:", metaData, directive)) + { + SequencePtr seq = SequencePtr::dynamicCast(cont); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && builtin->kind() == Builtin::KindByte) + { + return true; + } + } + } + + if(findMetaData("java:buffer", localMetaData, directive)) + { + SequencePtr seq = SequencePtr::dynamicCast(cont); if(seq) { BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); @@ -3139,57 +5315,125 @@ Slice::JavaGenerator::MetaDataVisitor::validateType(const SyntaxTreeBasePtr& p, builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) { - continue; + return true; } - } - emitWarning(file, line, "ignoring invalid metadata `" + *i + "'"); } - else if(i->find("java:protobuf:") == 0 || i->find("java:serializable:") == 0) - { - // - // Only valid in sequence defintion which is checked in visitSequence - // - emitWarning(file, line, "ignoring invalid metadata `" + *i + "'"); - } - else if(i->find("delegate") == 0) + } + + return false; +} + +bool +Slice::JavaGenerator::getDictionaryTypes(const DictionaryPtr& dict, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType, + bool local) const +{ + // + // Get the types of the key and value. + // + string keyTypeStr = typeToObjectString(dict->keyType(), TypeModeIn, package, StringList(), true, local); + string valueTypeStr = typeToObjectString(dict->valueType(), TypeModeIn, package, StringList(), true, local); + + // + // Collect metadata for a custom type. + // + if(getTypeMetaData(metaData, instanceType, formalType) || + getTypeMetaData(dict->getMetaData(), instanceType, formalType)) + { + assert(!instanceType.empty()); + if(formalType.empty()) { - ClassDefPtr cl = ClassDefPtr::dynamicCast(p); - if(cl && cl->isDelegate()) - { - continue; - } - emitWarning(file, line, "ignoring invalid metadata `" + *i + "'"); + formalType = "java.util.Map<" + keyTypeStr + ", " + valueTypeStr + ">"; } + return true; } + + // + // Return a default type for the platform. + // + instanceType = "java.util.HashMap<" + keyTypeStr + ", " + valueTypeStr + ">"; + formalType = "java.util.Map<" + keyTypeStr + ", " + valueTypeStr + ">"; + return false; } -void -Slice::JavaGenerator::MetaDataVisitor::validateGetSet(const SyntaxTreeBasePtr& p, const StringList& metaData, - const string& file, const string& line) +bool +Slice::JavaGenerator::getSequenceTypes(const SequencePtr& seq, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType, + bool local) const { - for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); ++i) + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin) { - // - // The "getset" metadata can only be specified on a class, struct, exception or data member. - // - if((*i) == "java:getset" && - (!ClassDefPtr::dynamicCast(p) && !StructPtr::dynamicCast(p) && !ExceptionPtr::dynamicCast(p) && - !DataMemberPtr::dynamicCast(p))) + if(builtin->kind() == Builtin::KindByte) { - string str; - ContainedPtr cont = ContainedPtr::dynamicCast(p); - if(cont) + string prefix = "java:serializable:"; + string meta; + if(seq->findMetaData(prefix, meta)) { - str = cont->kindOf(); + instanceType = formalType = meta.substr(prefix.size()); + return true; } - else + prefix = "java:protobuf:"; + if(seq->findMetaData(prefix, meta)) { - BuiltinPtr b = BuiltinPtr::dynamicCast(p); - assert(b); - str = b->typeId(); + instanceType = formalType = meta.substr(prefix.size()); + return true; } - emitWarning(file, line, "invalid metadata for " + str); } + + if((builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string prefix = "java:buffer"; + string meta; + string ignore; + if(seq->findMetaData(prefix, meta) || findMetaData(prefix, metaData, ignore)) + { + instanceType = formalType = typeToBufferString(seq->type()); + return true; + } + } + } + + // + // Collect metadata for a custom type. + // + if(getTypeMetaData(metaData, instanceType, formalType) || + getTypeMetaData(seq->getMetaData(), instanceType, formalType)) + { + assert(!instanceType.empty()); + if(formalType.empty()) + { + formalType = "java.util.List<" + + typeToObjectString(seq->type(), TypeModeIn, package, StringList(), true, local) + ">"; + } + return true; } + + // + // The default mapping is a native array. + // + instanceType = formalType = typeToString(seq->type(), TypeModeIn, package, metaData, true, false, local) + "[]"; + return false; +} + +JavaOutput* +Slice::JavaGenerator::createOutput() +{ + return new JavaOutput; +} + +void +Slice::JavaGenerator::validateMetaData(const UnitPtr& u) +{ + MetaDataVisitor visitor; + u->visit(&visitor, true); } diff --git a/cpp/src/Slice/JavaUtil.h b/cpp/src/Slice/JavaUtil.h index 6473f406e0e..d9375be077e 100644 --- a/cpp/src/Slice/JavaUtil.h +++ b/cpp/src/Slice/JavaUtil.h @@ -59,11 +59,11 @@ public: virtual void printHeader(); }; -class JavaGenerator : private ::IceUtil::noncopyable +class JavaCompatGenerator : private ::IceUtil::noncopyable { public: - virtual ~JavaGenerator(); + virtual ~JavaCompatGenerator(); // // Validate all metadata in the unit with a "java:" prefix. @@ -74,7 +74,7 @@ public: protected: - JavaGenerator(const std::string&); + JavaCompatGenerator(const std::string&); // // Given the fully-scoped Java class name, create any intermediate @@ -220,33 +220,170 @@ protected: private: - class MetaDataVisitor : public ParserVisitor + std::string _dir; + ::IceUtilInternal::Output* _out; + mutable std::map<std::string, std::string> _filePackagePrefix; +}; + +class JavaGenerator : private ::IceUtil::noncopyable +{ +public: + + virtual ~JavaGenerator(); + + // + // Validate all metadata in the unit with a "java:" prefix. + // + static void validateMetaData(const UnitPtr&); + + void close(); + +protected: + + JavaGenerator(const std::string&); + + // + // Given the fully-scoped Java class name, create any intermediate + // package directories and open the class file, + // + void open(const std::string&, const std::string&); + + ::IceUtilInternal::Output& output() const; + + // + // Check a symbol against any of the Java keywords. If a + // match is found, return the symbol with a leading underscore. + // + std::string fixKwd(const std::string&) const; + + // + // Convert a Slice scoped name into a Java name. + // + std::string convertScopedName(const std::string&, + const std::string& = std::string(), + const std::string& = std::string()) const; + + + // + // Returns the package prefix for a give Slice file. + // + std::string getPackagePrefix(const ContainedPtr&) const; + + // + // Returns the Java package of a Contained entity. + // + std::string getPackage(const ContainedPtr&) const; + + // + // Returns the Java name for a Contained entity. If the optional + // package argument matches the entity's package name, then the + // package is removed from the result. + // + std::string getAbsolute(const ContainedPtr&, + const std::string& = std::string(), + const std::string& = std::string(), + const std::string& = std::string()) const; + + // + // Return the method call necessary to obtain the static type ID for an object type. + // + std::string getStaticId(const TypePtr&, const std::string&) const; + + // + // Determines whether an operation should use the optional mapping. + // + bool useOptionalMapping(const OperationPtr&); + + // + // Returns the optional type corresponding to the given Slice type. + // + std::string getOptionalFormat(const TypePtr&); + + // + // Get the Java name for a type. If an optional scope is provided, + // the scope will be removed from the result if possible. + // + enum TypeMode { - public: - - virtual bool visitUnitStart(const UnitPtr&); - virtual bool visitModuleStart(const ModulePtr&); - virtual void visitClassDecl(const ClassDeclPtr&); - virtual bool visitClassDefStart(const ClassDefPtr&); - virtual bool visitExceptionStart(const ExceptionPtr&); - virtual bool visitStructStart(const StructPtr&); - virtual void visitOperation(const OperationPtr&); - virtual void visitDataMember(const DataMemberPtr&); - virtual void visitSequence(const SequencePtr&); - virtual void visitDictionary(const DictionaryPtr&); - virtual void visitEnum(const EnumPtr&); - virtual void visitConst(const ConstPtr&); - - private: - - StringList getMetaData(const ContainedPtr&); - void validateType(const SyntaxTreeBasePtr&, const StringList&, const std::string&, const std::string&); - void validateGetSet(const SyntaxTreeBasePtr&, const StringList&, const std::string&, const std::string&); - - StringSet _history; + TypeModeIn, + TypeModeOut, + TypeModeMember, + TypeModeReturn }; + std::string typeToString(const TypePtr&, TypeMode, const std::string& = std::string(), + const StringList& = StringList(), bool = true, bool = false, bool = false) const; - friend class JavaGenerator::MetaDataVisitor; + // + // Get the Java object name for a type. For primitive types, this returns the + // Java class type (e.g., Integer). For all other types, this function delegates + // to typeToString. + // + std::string typeToObjectString(const TypePtr&, TypeMode, const std::string& = std::string(), + const StringList& = StringList(), bool = true, bool = false) const; + + // + // Generate code to marshal or unmarshal a type. + // + enum OptionalMode + { + OptionalNone, + OptionalInParam, + OptionalOutParam, + OptionalReturnParam, + OptionalMember + }; + + void writeMarshalUnmarshalCode(::IceUtilInternal::Output&, const std::string&, const TypePtr&, OptionalMode, + bool, int, const std::string&, bool, int&, const StringList& = StringList(), + const std::string& patchParams = ""); + + // + // Generate code to marshal or unmarshal a dictionary type. + // + void writeDictionaryMarshalUnmarshalCode(::IceUtilInternal::Output&, const std::string&, const DictionaryPtr&, + const std::string&, bool, int&, bool, + const StringList& = StringList()); + + // + // Generate code to marshal or unmarshal a sequence type. + // + void writeSequenceMarshalUnmarshalCode(::IceUtilInternal::Output&, const std::string&, const SequencePtr&, + const std::string&, bool, int&, bool, const StringList& = StringList()); + + // + // Search metadata for an entry with the given prefix and return the entire string. + // + static bool findMetaData(const std::string&, const StringList&, std::string&); + + // + // Get custom type metadata. If metadata is found, the abstract and + // concrete types are extracted and the function returns true. If an + // abstract type is not specified, it is set to an empty string. + // + static bool getTypeMetaData(const StringList&, std::string&, std::string&); + + // + // Determine whether a custom type is defined. The function checks the + // metadata of the type's original definition, as well as any optional + // metadata that typically represents a data member or parameter. + // + static bool hasTypeMetaData(const TypePtr&, const StringList& = StringList()); + + // + // Obtain the concrete and abstract types for a dictionary or sequence type. + // The functions return true if a custom type was defined and false to indicate + // the default mapping was used. + // + bool getDictionaryTypes(const DictionaryPtr&, const std::string&, const StringList&, + std::string&, std::string&, bool) const; + bool getSequenceTypes(const SequencePtr&, const std::string&, const StringList&, std::string&, std::string&, + bool) const; + + virtual JavaOutput* createOutput(); + + static const std::string _getSetMetaData; + +private: std::string _dir; ::IceUtilInternal::Output* _out; diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp index 825c9c8e3fb..e4bb71d4824 100644 --- a/cpp/src/Slice/Parser.cpp +++ b/cpp/src/Slice/Parser.cpp @@ -63,6 +63,23 @@ filterOrderedOptionalDataMembers(const DataMemberList& members) return result; } +void +sortOptionalParameters(ParamDeclList& params) +{ + // + // Sort optional parameters by tag. + // + class SortFn + { + public: + static bool compare(const ParamDeclPtr& lhs, const ParamDeclPtr& rhs) + { + return lhs->tag() < rhs->tag(); + } + }; + params.sort(SortFn::compare); +} + bool isMutableAfterReturnType(const TypePtr& type) { @@ -5136,7 +5153,7 @@ Slice::Operation::inParameters() const for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p); - if(!q->isOutParam()) + if(q && !q->isOutParam()) { result.push_back(q); } @@ -5144,6 +5161,25 @@ Slice::Operation::inParameters() const return result; } +void +Slice::Operation::inParameters(ParamDeclList& required, ParamDeclList& optional) const +{ + const ParamDeclList params = inParameters(); + for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli) + { + if((*pli)->optional()) + { + optional.push_back(*pli); + } + else + { + required.push_back(*pli); + } + } + + sortOptionalParameters(optional); +} + ParamDeclList Slice::Operation::outParameters() const { @@ -5151,7 +5187,7 @@ Slice::Operation::outParameters() const for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p); - if(q->isOutParam()) + if(q && q->isOutParam()) { result.push_back(q); } @@ -5159,6 +5195,25 @@ Slice::Operation::outParameters() const return result; } +void +Slice::Operation::outParameters(ParamDeclList& required, ParamDeclList& optional) const +{ + const ParamDeclList params = outParameters(); + for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli) + { + if((*pli)->optional()) + { + optional.push_back(*pli); + } + else + { + required.push_back(*pli); + } + } + + sortOptionalParameters(optional); +} + ExceptionList Slice::Operation::throws() const { @@ -5311,12 +5366,25 @@ Slice::Operation::returnsData() const } bool +Slice::Operation::returnsMultipleValues() const +{ + int count = outParameters().size(); + + if(returnType()) + { + ++count; + } + + return count > 1; +} + +bool Slice::Operation::sendsOptionals() const { - ParamDeclList pdl = parameters(); + ParamDeclList pdl = inParameters(); for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i) { - if(!(*i)->isOutParam() && (*i)->optional()) + if((*i)->optional()) { return true; } @@ -6207,6 +6275,11 @@ Slice::Unit::parse(const string& filename, FILE* file, bool debug, Slice::Featur popContainer(); assert(_definitionContextStack.size() == 1); popDefinitionContext(); + + if(!checkUndefinedTypes()) + { + status = EXIT_FAILURE; + } } Slice::unit = 0; @@ -6305,6 +6378,113 @@ Slice::Unit::eraseWhiteSpace(string& s) } } +bool +Slice::Unit::checkUndefinedTypes() +{ + class Visitor : public ParserVisitor + { + public: + + Visitor(int& errors) : + _errors(errors), + _local(false) + { + } + + virtual bool visitClassDefStart(const ClassDefPtr& p) + { + _local = p->isLocal(); + return true; + } + + virtual bool visitExceptionStart(const ExceptionPtr& p) + { + _local = p->isLocal(); + return true; + } + + virtual bool visitStructStart(const StructPtr& p) + { + _local = p->isLocal(); + return true; + } + + virtual void visitOperation(const OperationPtr& p) + { + if(p->returnType()) + { + checkUndefined(p->returnType(), "return type", p->file(), p->line()); + } + ParamDeclList params = p->parameters(); + for(ParamDeclList::const_iterator q = params.begin(); q != params.end(); ++q) + { + checkUndefined((*q)->type(), "parameter " + (*q)->name(), (*q)->file(), (*q)->line()); + } + } + + virtual void visitParamDecl(const ParamDeclPtr& p) + { + checkUndefined(p->type(), "parameter " + p->name(), p->file(), p->line()); + } + + virtual void visitDataMember(const DataMemberPtr& p) + { + checkUndefined(p->type(), "member " + p->name(), p->file(), p->line()); + } + + virtual void visitSequence(const SequencePtr& p) + { + _local = p->isLocal(); + checkUndefined(p->type(), "element type", p->file(), p->line()); + } + + virtual void visitDictionary(const DictionaryPtr& p) + { + _local = p->isLocal(); + checkUndefined(p->keyType(), "key type", p->file(), p->line()); + checkUndefined(p->valueType(), "value type", p->file(), p->line()); + } + + private: + + void checkUndefined(const TypePtr& type, const string& desc, const string& file, const string& line) + { + // + // See ICE-6867. Any use of a proxy requires the full type definition, as does any + // use of a class in a non-local context. + // + ProxyPtr p = ProxyPtr::dynamicCast(type); + if(p) + { + const ClassDeclPtr cl = p->_class(); + if(!cl->definition()) + { + ostringstream ostr; + ostr << desc << " uses a proxy for undefined type `" << cl->scoped() << "'"; + emitError(file, line, ostr.str()); + _errors++; + } + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl && !cl->definition() && !_local) + { + ostringstream ostr; + ostr << desc << " refers to undefined type `" << cl->scoped() << "'"; + emitError(file, line, ostr.str()); + _errors++; + } + } + + int& _errors; + bool _local; + }; + + Visitor v(_errors); + visit(&v, true); + return _errors == 0; +} + // ---------------------------------------------------------------------- // CICompare // ---------------------------------------------------------------------- diff --git a/cpp/src/Slice/Parser.h b/cpp/src/Slice/Parser.h index 3e5891db655..c26de803f13 100644 --- a/cpp/src/Slice/Parser.h +++ b/cpp/src/Slice/Parser.h @@ -598,7 +598,9 @@ public: ParamDeclPtr createParamDecl(const std::string&, const TypePtr&, bool, bool, int); ParamDeclList parameters() const; ParamDeclList inParameters() const; + void inParameters(ParamDeclList&, ParamDeclList&) const; ParamDeclList outParameters() const; + void outParameters(ParamDeclList&, ParamDeclList&) const; ExceptionList throws() const; void setExceptionList(const ExceptionList&); virtual ContainedType containedType() const; @@ -606,6 +608,7 @@ public: bool sendsClasses(bool) const; bool returnsClasses(bool) const; bool returnsData() const; + bool returnsMultipleValues() const; bool sendsOptionals() const; int attributes() const; FormatType format() const; @@ -1076,6 +1079,7 @@ private: Unit(bool, bool, bool, bool, const StringList&); static void eraseWhiteSpace(::std::string&); + bool checkUndefinedTypes(); bool _ignRedefs; bool _all; diff --git a/cpp/src/Slice/Preprocessor.cpp b/cpp/src/Slice/Preprocessor.cpp index 26f4bee7db1..dc7c4abdf77 100644 --- a/cpp/src/Slice/Preprocessor.cpp +++ b/cpp/src/Slice/Preprocessor.cpp @@ -140,7 +140,7 @@ namespace { vector<string> -baseArgs(vector<string> args, bool keepComments, const string& extraArgs, const string& fileName) +baseArgs(vector<string> args, bool keepComments, const vector<string>& extraArgs, const string& fileName) { if(keepComments) { @@ -161,10 +161,7 @@ baseArgs(vector<string> args, bool keepComments, const string& extraArgs, const args.push_back(os.str()); } - if(!extraArgs.empty()) - { - args.push_back(extraArgs); - } + copy(extraArgs.begin(), extraArgs.end(), back_inserter(args)); args.push_back(fileName); return args; } @@ -172,7 +169,15 @@ baseArgs(vector<string> args, bool keepComments, const string& extraArgs, const } FILE* -Slice::Preprocessor::preprocess(bool keepComments, const string& extraArgs) +Slice::Preprocessor::preprocess(bool keepComments, const string& extraArg) +{ + vector<string> args; + args.push_back(extraArg); + return preprocess(keepComments, args); +} + +FILE* +Slice::Preprocessor::preprocess(bool keepComments, const vector<string>& extraArgs) { if(!checkInputFile()) { @@ -287,7 +292,17 @@ Slice::Preprocessor::preprocess(bool keepComments, const string& extraArgs) bool Slice::Preprocessor::printMakefileDependencies(ostream& out, Language lang, const vector<string>& includePaths, - const string& extraArgs, const string& cppSourceExt, + const string& extraArg, const string& cppSourceExt, + const string& optValue) +{ + vector<string> extraArgs; + extraArgs.push_back(extraArg); + return printMakefileDependencies(out, lang, includePaths, extraArgs, cppSourceExt, optValue); +} + +bool +Slice::Preprocessor::printMakefileDependencies(ostream& out, Language lang, const vector<string>& includePaths, + const vector<string>& extraArgs, const string& cppSourceExt, const string& optValue) { if(!checkInputFile()) diff --git a/cpp/src/Slice/Preprocessor.h b/cpp/src/Slice/Preprocessor.h index 80f8acf4d66..f237a41b3f1 100644 --- a/cpp/src/Slice/Preprocessor.h +++ b/cpp/src/Slice/Preprocessor.h @@ -29,12 +29,16 @@ public: ~Preprocessor(); FILE* preprocess(bool, const std::string& = ""); + FILE* preprocess(bool, const std::vector<std::string>&); bool close(); enum Language { CPlusPlus, Java, CSharp, Python, Ruby, PHP, JavaScript, JavaScriptJSON, ObjC, SliceXML }; bool printMakefileDependencies(std::ostream&, Language, const std::vector<std::string>&, const std::string& = "", const std::string& = "cpp", const std::string& = ""); + bool printMakefileDependencies(std::ostream&, Language, const std::vector<std::string>&, + const std::vector<std::string>&, const std::string& = "cpp", + const std::string& = ""); std::string getBaseName(); diff --git a/cpp/src/slice2java/Gen.cpp b/cpp/src/slice2java/Gen.cpp index 3e526d761ff..192281628a0 100644 --- a/cpp/src/slice2java/Gen.cpp +++ b/cpp/src/slice2java/Gen.cpp @@ -24,6 +24,9 @@ using namespace Slice; using namespace IceUtil; using namespace IceUtilInternal; +namespace +{ + string u16CodePoint(unsigned short value) { @@ -47,55 +50,51 @@ writeU8Buffer(const vector<unsigned char>& u8buffer, ::IceUtilInternal::Output& } } -static string +string sliceModeToIceMode(Operation::Mode opMode) { - string mode; + string mode = "com.zeroc.Ice.OperationMode."; switch(opMode) { - case Operation::Normal: - { - mode = "Ice.OperationMode.Normal"; - break; - } - case Operation::Nonmutating: - { - mode = "Ice.OperationMode.Nonmutating"; - break; - } - case Operation::Idempotent: - { - mode = "Ice.OperationMode.Idempotent"; - break; - } - default: - { - assert(false); - break; - } + case Operation::Normal: + mode = "null"; // shorthand for most common case + break; + case Operation::Nonmutating: + mode += "Nonmutating"; + break; + case Operation::Idempotent: + mode += "Idempotent"; + break; + default: + assert(false); + break; } return mode; } -static string +string opFormatTypeToString(const OperationPtr& op) { + string format = "com.zeroc.Ice.FormatType."; switch(op->format()) { case DefaultFormat: - return "Ice.FormatType.DefaultFormat"; + format = "null"; // shorthand for most common case + break; case CompactFormat: - return "Ice.FormatType.CompactFormat"; + format += "CompactFormat"; + break; case SlicedFormat: - return "Ice.FormatType.SlicedFormat"; + format += "SlicedFormat"; + break; default: assert(false); + break; } - - return "???"; + return format; } -static string +string getDeprecateReason(const ContainedPtr& p1, const ContainedPtr& p2, const string& type) { string deprecateMetadata, deprecateReason; @@ -111,6 +110,7 @@ getDeprecateReason(const ContainedPtr& p1, const ContainedPtr& p2, const string& return deprecateReason; } +#if TBD string initValue(const TypePtr& p) { @@ -180,6 +180,16 @@ writeParamList(Output& out, vector<string> params, bool end = true, bool newLine out.restoreIndent(); } } +#endif + +bool isValue(const TypePtr& type) +{ + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + return (b && b->usesClasses()) || cl; +} + +} Slice::JavaVisitor::JavaVisitor(const string& dir) : JavaGenerator(dir) @@ -190,378 +200,450 @@ Slice::JavaVisitor::~JavaVisitor() { } -ParamDeclList -Slice::JavaVisitor::getOutParams(const OperationPtr& op) +string +Slice::JavaVisitor::getResultType(const OperationPtr& op, const string& package, bool object, bool dispatch) { - ParamDeclList outParams; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator i = paramList.begin(); i != paramList.end(); ++i) + if(dispatch && op->hasMarshaledResult()) { - if((*i)->isOutParam()) + ContainedPtr c = ContainedPtr::dynamicCast(op->container()); + assert(c); + string abs = getAbsolute(c, package); + string name = op->name(); + name[0] = toupper(static_cast<unsigned char>(name[0])); + return abs + "." + name + "MarshaledResult"; + } + else if(op->returnsMultipleValues()) + { + ContainedPtr c = ContainedPtr::dynamicCast(op->container()); + assert(c); + string abs = getAbsolute(c, package); + string name = op->name(); + name[0] = toupper(static_cast<unsigned char>(name[0])); + return abs + "." + name + "Result"; + } + else + { + TypePtr type = op->returnType(); + bool optional = op->returnIsOptional(); + if(!type) { - outParams.push_back(*i); + const ParamDeclList outParams = op->outParameters(); + if(!outParams.empty()) + { + assert(outParams.size() == 1); + type = outParams.front()->type(); + optional = outParams.front()->optional(); + } + } + if(type) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + assert(cl); + if(optional) + { + return typeToString(type, TypeModeReturn, package, op->getMetaData(), true, true, cl->isLocal()); + } + else if(object) + { + return typeToObjectString(type, TypeModeReturn, package, op->getMetaData(), true, cl->isLocal()); + } + else + { + return typeToString(type, TypeModeReturn, package, op->getMetaData(), true, false, cl->isLocal()); + } + } + else + { + return object ? "Void" : "void"; } } - return outParams; } -vector<string> -Slice::JavaVisitor::getParams(const OperationPtr& op, const string& package, bool local, bool optionalMapping) +void +Slice::JavaVisitor::writeResultType(Output& out, const OperationPtr& op, const string& package) { - vector<string> params; + string opName = op->name(); + opName[0] = toupper(static_cast<unsigned char>(opName[0])); - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + out << sp << nl << "public static class " << opName << "Result"; + out << sb; + + // + // Make sure none of the out parameters are named "returnValue". + // + string retval = "returnValue"; + const ParamDeclList outParams = op->outParameters(); + for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p) { - StringList metaData = (*q)->getMetaData(); - bool optional = (*q)->optional(); - if(optional && (local || (*q)->isOutParam())) + if((*p)->name() == "returnValue") { - optional = optionalMapping; + retval = "_returnValue"; + break; } - string typeString = typeToString((*q)->type(), (*q)->isOutParam() ? TypeModeOut : TypeModeIn, package, - metaData, true, optional); - params.push_back(typeString + ' ' + fixKwd((*q)->name())); } - return params; -} + const TypePtr ret = op->returnType(); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + assert(cl); -vector<string> -Slice::JavaVisitor::getParamsProxy(const OperationPtr& op, const string& package, bool final, bool optionalMapping) -{ - vector<string> params; + // + // Default constructor. + // + out << nl << "public " << opName << "Result()"; + out << sb; + out << eb; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + // + // One-shot constructor. + // + out << sp << nl << "public " << opName << "Result" << spar; + if(ret) { - bool optional; - if((*q)->optional()) + out << (typeToString(ret, TypeModeIn, package, op->getMetaData(), true, op->returnIsOptional(), cl->isLocal()) + + " " + retval); + } + for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p) + { + out << (typeToString((*p)->type(), TypeModeIn, package, (*p)->getMetaData(), true, (*p)->optional(), + cl->isLocal()) + " " + fixKwd((*p)->name())); + } + out << epar; + out << sb; + if(ret) + { + out << nl << "this." << retval << " = " << retval << ';'; + } + for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p) + { + const string name = fixKwd((*p)->name()); + out << nl << "this." << name << " = " << name << ';'; + } + out << eb; + + // + // Members. + // + out << sp; + if(ret) + { + out << nl << "public " << typeToString(ret, TypeModeIn, package, op->getMetaData(), true, + op->returnIsOptional(), cl->isLocal()) + << ' ' << retval << ';'; + } + + for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p) + { + out << nl << "public " << typeToString((*p)->type(), TypeModeIn, package, (*p)->getMetaData(), true, + (*p)->optional(), cl->isLocal()) + << ' ' << fixKwd((*p)->name()) << ';'; + } + + if(!cl->isLocal()) + { + ParamDeclList required, optional; + op->outParameters(required, optional); + + out << sp << nl << "public void write(com.zeroc.Ice.OutputStream __os)"; + out << sb; + + int iter = 0; + for(ParamDeclList::const_iterator pli = required.begin(); pli != required.end(); ++pli) { - optional = (*q)->isOutParam() ? true : optionalMapping; + const string paramName = fixKwd((*pli)->name()); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalNone, false, 0, paramName, true, iter, + (*pli)->getMetaData()); } - else + + if(ret && !op->returnIsOptional()) { - optional = false; + writeMarshalUnmarshalCode(out, package, ret, OptionalNone, false, 0, retval, true, iter, op->getMetaData()); } - StringList metaData = (*q)->getMetaData(); - string typeString = typeToString((*q)->type(), (*q)->isOutParam() ? TypeModeOut : TypeModeIn, package, - metaData, true, optional); - if(final) + // + // Handle optional parameters. + // + bool checkReturnType = op->returnIsOptional(); + + for(ParamDeclList::const_iterator pli = optional.begin(); pli != optional.end(); ++pli) { - typeString = "final " + typeString; + if(checkReturnType && op->returnTag() < (*pli)->tag()) + { + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, true, op->returnTag(), retval, true, + iter, op->getMetaData()); + checkReturnType = false; + } + + const string paramName = fixKwd((*pli)->name()); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalOutParam, true, (*pli)->tag(), paramName, + true, iter, (*pli)->getMetaData()); } - params.push_back(typeString + ' ' + fixKwd((*q)->name())); - } - return params; -} + if(checkReturnType) + { + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, true, op->returnTag(), retval, true, iter, + op->getMetaData()); + } -vector<string> -Slice::JavaVisitor::getInOutParams(const OperationPtr& op, const string& package, ParamDir paramType, bool /*proxy*/, - bool optionalMapping) -{ - vector<string> params; + out << eb; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) - { - if((*q)->isOutParam() == (paramType == OutParam)) + out << sp << nl << "public void read(com.zeroc.Ice.InputStream __is)"; + out << sb; + + iter = 0; + for(ParamDeclList::const_iterator pli = required.begin(); pli != required.end(); ++pli) { - bool optional = optionalMapping && (*q)->optional(); - string typeString = typeToString((*q)->type(), paramType == InParam ? TypeModeIn : TypeModeOut, package, - (*q)->getMetaData(), true, optional); - params.push_back(typeString + ' ' + fixKwd((*q)->name())); + const string paramName = fixKwd((*pli)->name()); + const string patchParams = getPatcher((*pli)->type(), package, paramName, false); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalNone, false, 0, paramName, false, iter, + (*pli)->getMetaData(), patchParams); } - } - return params; -} + if(ret && !op->returnIsOptional()) + { + const string patchParams = getPatcher(ret, package, retval, false); + writeMarshalUnmarshalCode(out, package, ret, OptionalNone, false, 0, retval, false, iter, op->getMetaData(), + patchParams); + } -vector<string> -Slice::JavaVisitor::getParamsAsync(const OperationPtr& op, const string& package, bool amd, bool optionalMapping) -{ - vector<string> params = getInOutParams(op, package, InParam, !amd, optionalMapping); + // + // Handle optional parameters. + // + checkReturnType = op->returnIsOptional(); + + for(ParamDeclList::const_iterator pli = optional.begin(); pli != optional.end(); ++pli) + { + if(checkReturnType && op->returnTag() < (*pli)->tag()) + { + const string patchParams = getPatcher(ret, package, retval, true); + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, true, op->returnTag(), retval, false, + iter, op->getMetaData(), patchParams); + checkReturnType = false; + } - string name = op->name(); - ContainerPtr container = op->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - string classNameAsync = getAbsolute(cl, package, amd ? "AMD_" : "AMI_", '_' + name); - params.insert(params.begin(), classNameAsync + " __cb"); + const string paramName = fixKwd((*pli)->name()); + const string patchParams = getPatcher((*pli)->type(), package, paramName, true); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalOutParam, true, (*pli)->tag(), paramName, + false, iter, (*pli)->getMetaData(), patchParams); + } - return params; + if(checkReturnType) + { + const string patchParams = getPatcher(ret, package, retval, true); + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, true, op->returnTag(), retval, false, + iter, op->getMetaData(), patchParams); + } + + out << eb; + } + + out << eb; } -vector<string> -Slice::JavaVisitor::getParamsAsyncCB(const OperationPtr& op, const string& package, bool /*amd*/, bool optionalMapping) +void +Slice::JavaVisitor::writeMarshaledResultType(Output& out, const OperationPtr& op, const string& package) { - vector<string> params; + string opName = op->name(); + opName[0] = toupper(static_cast<unsigned char>(opName[0])); - TypePtr ret = op->returnType(); + out << sp << nl << "public static class " << opName << "MarshaledResult implements com.zeroc.Ice.MarshaledResult"; + out << sb; + + const TypePtr ret = op->returnType(); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + assert(cl); + const ParamDeclList outParams = op->outParameters(); + const string retval = "__ret"; + + out << sp << nl << "public " << opName << "MarshaledResult" << spar; if(ret) { - string retS = typeToString(ret, TypeModeIn, package, op->getMetaData(), true, - optionalMapping && op->returnIsOptional()); - params.push_back(retS + " __ret"); + out << (typeToString(ret, TypeModeIn, package, op->getMetaData(), true, op->returnIsOptional(), cl->isLocal()) + + " " + retval); + } + for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p) + { + out << (typeToString((*p)->type(), TypeModeIn, package, (*p)->getMetaData(), true, (*p)->optional(), + cl->isLocal()) + " " + fixKwd((*p)->name())); } + out << "com.zeroc.Ice.Current __current" << epar; + out << sb; + out << nl << "__os = com.zeroc.IceInternal.Incoming.createResponseOutputStream(__current);"; + out << nl << "__os.startEncapsulation(__current.encoding, " << opFormatTypeToString(op) << ");"; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + ParamDeclList required, optional; + op->outParameters(required, optional); + int iter = 0; + for(ParamDeclList::const_iterator pli = required.begin(); pli != required.end(); ++pli) + { + const string paramName = fixKwd((*pli)->name()); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalNone, false, 0, paramName, true, iter, + (*pli)->getMetaData()); + } + + if(ret && !op->returnIsOptional()) { - if((*q)->isOutParam()) + writeMarshalUnmarshalCode(out, package, ret, OptionalNone, false, 0, retval, true, iter, op->getMetaData()); + } + + // + // Handle optional parameters. + // + bool checkReturnType = op->returnIsOptional(); + + for(ParamDeclList::const_iterator pli = optional.begin(); pli != optional.end(); ++pli) + { + if(checkReturnType && op->returnTag() < (*pli)->tag()) { - string typeString = typeToString((*q)->type(), TypeModeIn, package, (*q)->getMetaData(), true, - optionalMapping && (*q)->optional()); - params.push_back(typeString + ' ' + fixKwd((*q)->name())); + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, true, op->returnTag(), retval, true, + iter, op->getMetaData()); + checkReturnType = false; } + + const string paramName = fixKwd((*pli)->name()); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalOutParam, true, (*pli)->tag(), paramName, + true, iter, (*pli)->getMetaData()); } - return params; -} + if(checkReturnType) + { + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, true, op->returnTag(), retval, true, iter, + op->getMetaData()); + } -namespace -{ + if(op->returnsClasses(false)) + { + out << nl << "__os.writePendingValues();"; + } -const char* builtinAsyncCallbackTable[] = -{ - "TwowayCallbackByte", - "TwowayCallbackBool", - "TwowayCallbackShort", - "TwowayCallbackInt", - "TwowayCallbackLong", - "TwowayCallbackFloat", - "TwowayCallbackDouble" -}; + out << nl << "__os.endEncapsulation();"; + + out << eb; + out << sp; + out << nl << "@Override" + << nl << "public com.zeroc.Ice.OutputStream getOutputStream()" + << sb + << nl << "return __os;" + << eb; + + out << sp; + out << nl << "private com.zeroc.Ice.OutputStream __os;"; + out << eb; } -string -Slice::JavaVisitor::getAsyncCallbackInterface(const OperationPtr& op, const string& package) +void +Slice::JavaVisitor::allocatePatcher(Output& out, const TypePtr& type, const string& package, const string& name) { - TypePtr ret = op->returnType(); - ParamDeclList outParams = getOutParams(op); - bool throws = !op->throws().empty(); - const string suffix = throws ? "UE" : ""; + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + assert((b && b->usesClasses()) || cl); - if(!ret && outParams.empty()) + string clsName; + if(b || cl->isInterface()) { - return throws ? "Ice.TwowayCallbackVoidUE" : "Ice.OnewayCallback"; - } - else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) - { - TypePtr t = ret ? ret : outParams.front()->type(); - bool optional = ret ? op->returnIsOptional() : outParams.front()->optional(); - BuiltinPtr builtin = BuiltinPtr::dynamicCast(t); - if(builtin && !optional) - { - const string prefix = "Ice."; - switch(builtin->kind()) - { - case Builtin::KindByte: - case Builtin::KindBool: - case Builtin::KindShort: - case Builtin::KindInt: - case Builtin::KindLong: - case Builtin::KindFloat: - case Builtin::KindDouble: - { - return prefix + builtinAsyncCallbackTable[builtin->kind()] + suffix; - } - default: - { - break; - } - } - } - - return "Ice.TwowayCallbackArg1" + suffix + "<" + - typeToString(t, TypeModeIn, package, op->getMetaData(), true, optional) + ">"; + clsName = "com.zeroc.Ice.Value"; } else { - ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); - return "_Callback_" + cl->name() + "_" + op->name(); + clsName = getAbsolute(cl, package); } + + out << nl << "com.zeroc.IceInternal.Patcher<" << clsName << "> " << name << " = new com.zeroc.IceInternal.Patcher<" + << clsName << ">(" << clsName << ".class, " << clsName << ".ice_staticId);"; } string -Slice::JavaVisitor::getAsyncCallbackBaseClass(const OperationPtr& op, bool functional) +Slice::JavaVisitor::getPatcher(const TypePtr& type, const string& package, const string& dest, bool optionalMapping) { - assert(op->returnsData()); - TypePtr ret = op->returnType(); - ParamDeclList outParams = getOutParams(op); - - bool throws = !op->throws().empty(); - const string suffix = throws ? "UE" : ""; - if(!ret && outParams.empty()) - { - assert(throws); - return functional ? - "IceInternal.Functional_TwowayCallbackVoidUE" : - "IceInternal.TwowayCallback implements Ice.TwowayCallbackVoidUE"; - } - else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + ostringstream ostr; + if((b && b->usesClasses()) || cl) { - TypePtr t = ret ? ret : outParams.front()->type(); - bool optional = ret ? op->returnIsOptional() : outParams.front()->optional(); - BuiltinPtr builtin = BuiltinPtr::dynamicCast(t); - if(builtin && !optional) + string clsName; + if(b || cl->isInterface()) { - switch(builtin->kind()) - { - case Builtin::KindByte: - case Builtin::KindBool: - case Builtin::KindShort: - case Builtin::KindInt: - case Builtin::KindLong: - case Builtin::KindFloat: - case Builtin::KindDouble: - { - ostringstream os; - os << (functional ? "IceInternal.Functional_" : "IceInternal.TwowayCallback implements Ice.") - << builtinAsyncCallbackTable[builtin->kind()] + suffix; - return os.str(); - } - default: - { - break; - } - } - } - - ostringstream os; - if(functional) - { - os << "IceInternal.Functional_TwowayCallbackArg1"; + clsName = "com.zeroc.Ice.Value"; } else { - os << "IceInternal.TwowayCallback implements Ice.TwowayCallbackArg1"; + clsName = getAbsolute(cl, package); } - os << suffix << "<" << typeToString(t, TypeModeIn, getPackage(op), op->getMetaData(), true, optional) + ">"; - return os.str(); - } - else - { - ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); - ostringstream os; - if(functional) + + ostr << "new com.zeroc.IceInternal.Patcher<" << clsName << ">(" << clsName << ".class, " + << clsName << ".ice_staticId, " << "__v -> "; + if(optionalMapping) { - os << "IceInternal.Functional_TwowayCallback" << suffix << " implements "; + ostr << dest << " = java.util.Optional.ofNullable(__v)"; } else { - os << "IceInternal.TwowayCallback implements "; + ostr << dest << " = __v"; } - os << "_Callback_" << cl->name() << "_" << op->name(); - return os.str(); + ostr << ')'; } + return ostr.str(); } string -Slice::JavaVisitor::getLambdaResponseCB(const OperationPtr& op, const string& package) +Slice::JavaVisitor::getFutureType(const OperationPtr& op, const string& package) { - TypePtr ret = op->returnType(); - ParamDeclList outParams = getOutParams(op); - if(!ret && outParams.empty()) - { - return "IceInternal.Functional_VoidCallback"; - } - else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) + if(op->returnType() || op->outParameters().size() > 0) { - TypePtr t = ret ? ret : outParams.front()->type(); - bool optional = ret ? op->returnIsOptional() : outParams.front()->optional(); - BuiltinPtr builtin = BuiltinPtr::dynamicCast(t); - if(builtin && !optional) - { - static const char* builtinTable[] = - { - "IceInternal.Functional_ByteCallback", - "IceInternal.Functional_BoolCallback", - "IceInternal.Functional_ShortCallback", - "IceInternal.Functional_IntCallback", - "IceInternal.Functional_LongCallback", - "IceInternal.Functional_FloatCallback", - "IceInternal.Functional_DoubleCallback" - }; - switch(builtin->kind()) - { - case Builtin::KindByte: - case Builtin::KindBool: - case Builtin::KindShort: - case Builtin::KindInt: - case Builtin::KindLong: - case Builtin::KindFloat: - case Builtin::KindDouble: - { - return builtinTable[builtin->kind()]; - } - default: - { - break; - } - } - } - - return "IceInternal.Functional_GenericCallback1<" + - typeToString(t, TypeModeIn, package, op->getMetaData(), true, optional) + ">"; + return "java.util.concurrent.CompletableFuture<" + getResultType(op, package, true, false) + ">"; } else { - ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); - return "FunctionalCallback_" + cl->name() + "_" + op->name() + "_Response"; + return "java.util.concurrent.CompletableFuture<Void>"; } } -vector<string> -Slice::JavaVisitor::getParamsAsyncLambda(const OperationPtr& op, const string& package, bool context, bool sentCB, - bool optionalMapping, bool inParams) +string +Slice::JavaVisitor::getFutureImplType(const OperationPtr& op, const string& package) { - vector<string> params; - - if(inParams) + if(op->returnType() || op->outParameters().size() > 0) { - params = getInOutParams(op, package, InParam, false, optionalMapping); + return "com.zeroc.IceInternal.OutgoingAsync<" + getResultType(op, package, true, false) + ">"; } - - if(context) + else { - params.push_back("java.util.Map<String, String> __ctx"); + return "com.zeroc.IceInternal.OutgoingAsync<Void>"; } +} - params.push_back(getLambdaResponseCB(op, package) + " __responseCb"); - - if(!op->throws().empty()) - { - params.push_back("IceInternal.Functional_GenericCallback1<Ice.UserException> __userExceptionCb"); - } +vector<string> +Slice::JavaVisitor::getParams(const OperationPtr& op, const string& package) +{ + vector<string> params; - params.push_back("IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb"); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + assert(cl); - if(sentCB) + const ParamDeclList paramList = op->inParameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) { - params.push_back("IceInternal.Functional_BoolCallback __sentCb"); + const string type = typeToString((*q)->type(), TypeModeIn, package, (*q)->getMetaData(), true, + (*q)->optional(), cl->isLocal()); + params.push_back(type + ' ' + fixKwd((*q)->name())); } return params; } vector<string> -Slice::JavaVisitor::getArgsAsyncLambda(const OperationPtr& op, const string& package, bool context, bool sentCB) +Slice::JavaVisitor::getParamsProxy(const OperationPtr& op, const string& package, bool optionalMapping) { - vector<string> args = getInOutArgs(op, InParam); - args.push_back(context ? "__ctx" : "null"); - args.push_back(context ? "true" : "false"); - args.push_back("false"); // __synchronous - args.push_back("__responseCb"); - if(!op->throws().empty()) + vector<string> params; + + ParamDeclList inParams = op->inParameters(); + for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q) { - args.push_back("__userExceptionCb"); + const string typeString = typeToString((*q)->type(), TypeModeIn, package, (*q)->getMetaData(), true, + optionalMapping && (*q)->optional()); + params.push_back(typeString + ' ' + fixKwd((*q)->name())); } - args.push_back("__exceptionCb"); - args.push_back(sentCB ? "__sentCb" : "null"); - return args; + + return params; } vector<string> @@ -579,175 +661,190 @@ Slice::JavaVisitor::getArgs(const OperationPtr& op) } vector<string> -Slice::JavaVisitor::getInOutArgs(const OperationPtr& op, ParamDir paramType) +Slice::JavaVisitor::getInArgs(const OperationPtr& op, bool patcher) { vector<string> args; - ParamDeclList paramList = op->parameters(); + ParamDeclList paramList = op->inParameters(); for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) { - if((*q)->isOutParam() == (paramType == OutParam)) + string s = fixKwd((*q)->name()); + if(patcher && isValue((*q)->type())) { - args.push_back(fixKwd((*q)->name())); + s += ".value"; } + args.push_back(s); } return args; } -vector<string> -Slice::JavaVisitor::getArgsAsync(const OperationPtr& op) -{ - vector<string> args = getInOutArgs(op, InParam); - args.insert(args.begin(), "__cb"); - return args; -} - -vector<string> -Slice::JavaVisitor::getArgsAsyncCB(const OperationPtr& op) +void +Slice::JavaVisitor::writeMarshalProxyParams(Output& out, const string& package, const OperationPtr& op, + bool optionalMapping) { - vector<string> args; - - TypePtr ret = op->returnType(); - if(ret) + int iter = 0; + ParamDeclList required, optional; + op->inParameters(required, optional); + for(ParamDeclList::const_iterator pli = required.begin(); pli != required.end(); ++pli) { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(ret); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(ret)) - { - args.push_back("__ret.value"); - } - else - { - args.push_back("__ret"); - } + string paramName = fixKwd((*pli)->name()); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalNone, false, 0, paramName, true, + iter, (*pli)->getMetaData()); } - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + // + // Handle optional parameters. + // + for(ParamDeclList::const_iterator pli = optional.begin(); pli != optional.end(); ++pli) { - if((*q)->isOutParam()) - { - BuiltinPtr builtin = BuiltinPtr::dynamicCast((*q)->type()); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast((*q)->type())) - { - args.push_back(fixKwd((*q)->name()) + ".value"); - } - else - { - args.push_back(fixKwd((*q)->name())); - } - } + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalInParam, optionalMapping, + (*pli)->tag(), fixKwd((*pli)->name()), true, iter, (*pli)->getMetaData()); } - return args; + if(op->sendsClasses(false)) + { + out << nl << "__os.writePendingValues();"; + } } void -Slice::JavaVisitor::writeMarshalUnmarshalParams(Output& out, const string& package, const ParamDeclList& params, - const OperationPtr& op, int& iter, bool marshal, bool optionalMapping, - bool dispatch) +Slice::JavaVisitor::writeUnmarshalProxyResults(Output& out, const string& package, const OperationPtr& op) { - ParamDeclList optionals; - for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli) + const ParamDeclList outParams = op->outParameters(); + const TypePtr ret = op->returnType(); + const string name = "__ret"; + + if(op->returnsMultipleValues()) + { + string resultType = getResultType(op, package, false, false); + out << nl << resultType << ' ' << name << " = new " << resultType << "();"; + out << nl << name << ".read(__is);"; + if(op->returnsClasses(false)) + { + out << nl << "__is.readPendingValues();"; + } + out << nl << "return " << name << ';'; + } + else { - if((*pli)->optional()) + string resultType = getResultType(op, package, false, false); + + bool optional; + TypePtr type; + int tag; + StringList metaData; + if(ret) { - optionals.push_back(*pli); + type = ret; + optional = op->returnIsOptional(); + tag = op->returnTag(); + metaData = op->getMetaData(); } else { - string paramName = fixKwd((*pli)->name()); - bool holder = marshal == dispatch; - string patchParams; - if(!marshal) - { - patchParams = paramName; - } - writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalNone, false, 0, paramName, marshal, - iter, holder, (*pli)->getMetaData(), patchParams); + assert(outParams.size() == 1); + optional = outParams.front()->optional(); + type = outParams.front()->type(); + tag = outParams.front()->tag(); + metaData = outParams.front()->getMetaData(); } - } - - TypePtr ret; - bool returnsObject = false; - if(op && op->returnType()) - { - ret = op->returnType(); - BuiltinPtr builtin = BuiltinPtr::dynamicCast(ret); - ClassDeclPtr cl = ClassDeclPtr::dynamicCast(ret); - returnsObject = (builtin && builtin->kind() == Builtin::KindObject) || cl; - const bool optional = optionalMapping && op->returnIsOptional(); + const bool val = isValue(type); - string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, optional); - bool holder = false; + int iter = 0; - if(!marshal) + if(optional) { - if(optional) + if(val) { - out << nl << retS << " __ret = new " << retS << "();"; + allocatePatcher(out, type, package, name); } - else if(returnsObject) + else { - out << nl << retS << "Holder __ret = new " << retS << "Holder();"; - holder = true; + out << nl << resultType << ' ' << name << ';'; } - else if(StructPtr::dynamicCast(ret)) + writeMarshalUnmarshalCode(out, package, type, ret ? OptionalReturnParam : OptionalOutParam, true, + tag, name, false, iter, metaData, name); + } + else + { + if(val) { - out << nl << retS << " __ret = null;"; + allocatePatcher(out, type, package, name); + } + else if(StructPtr::dynamicCast(type)) + { + out << nl << resultType << ' ' << name << " = null;"; } else { - out << nl << retS << " __ret;"; + out << nl << resultType << ' ' << name << ';'; } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, name, false, iter, metaData, name); } - if(!op->returnIsOptional()) + if(op->returnsClasses(false)) { - writeMarshalUnmarshalCode(out, package, ret, OptionalNone, false, 0, "__ret", marshal, iter, holder, - op->getMetaData()); + out << nl << "__is.readPendingValues();"; } - } - // - // Sort optional parameters by tag. - // - class SortFn - { - public: - static bool compare(const ParamDeclPtr& lhs, const ParamDeclPtr& rhs) + if(optional && val) { - return lhs->tag() < rhs->tag(); + out << nl << "return java.util.Optional.ofNullable(" << name << ".value);"; } - }; - optionals.sort(SortFn::compare); - - // - // Handle optional parameters. - // - bool checkReturnType = op && op->returnIsOptional(); + else if(val) + { + out << nl << "return " << name << ".value;"; + } + else + { + out << nl << "return " << name << ';'; + } + } +} - for(ParamDeclList::const_iterator pli = optionals.begin(); pli != optionals.end(); ++pli) +void +Slice::JavaVisitor::writeMarshalServantResults(Output& out, const string& package, const OperationPtr& op, + const string& param) +{ + if(op->returnsMultipleValues()) { - if(checkReturnType && op->returnTag() < (*pli)->tag()) + out << nl << param << ".write(__os);"; + } + else + { + const ParamDeclList params = op->outParameters(); + bool optional; + OptionalMode mode; + TypePtr type; + int tag; + StringList metaData; + if(op->returnType()) + { + type = op->returnType(); + optional = op->returnIsOptional(); + mode = optional ? OptionalReturnParam : OptionalNone; + tag = op->returnTag(); + metaData = op->getMetaData(); + } + else { - writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, optionalMapping, op->returnTag(), - "__ret", marshal, iter, false, op->getMetaData()); - checkReturnType = false; + assert(params.size() == 1); + optional = params.front()->optional(); + mode = optional ? OptionalOutParam : OptionalNone; + type = params.front()->type(); + tag = params.front()->tag(); + metaData = params.front()->getMetaData(); } - const bool holder = dispatch && (*pli)->isOutParam() && !optionalMapping; - - writeMarshalUnmarshalCode(out, package, (*pli)->type(), - (*pli)->isOutParam() ? OptionalOutParam : OptionalInParam, optionalMapping, - (*pli)->tag(), fixKwd((*pli)->name()), marshal, iter, holder, (*pli)->getMetaData()); + int iter = 0; + writeMarshalUnmarshalCode(out, package, type, mode, true, tag, param, true, iter, metaData); } - if(checkReturnType) + if(op->returnsClasses(false)) { - writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, optionalMapping, op->returnTag(), "__ret", - marshal, iter, false, op->getMetaData()); + out << nl << "__os.writePendingValues();"; } } @@ -781,7 +878,7 @@ Slice::JavaVisitor::writeMarshalDataMember(Output& out, const string& package, c if(!member->optional()) { writeMarshalUnmarshalCode(out, package, member->type(), OptionalNone, false, 0, fixKwd(member->name()), - true, iter, false, member->getMetaData()); + true, iter, member->getMetaData()); } else { @@ -789,216 +886,82 @@ Slice::JavaVisitor::writeMarshalDataMember(Output& out, const string& package, c << getOptionalFormat(member->type()) << "))"; out << sb; writeMarshalUnmarshalCode(out, package, member->type(), OptionalMember, false, 0, fixKwd(member->name()), true, - iter, false, member->getMetaData()); + iter, member->getMetaData()); out << eb; } } void -Slice::JavaVisitor::writeUnmarshalDataMember(Output& out, const string& package, const DataMemberPtr& member, - int& iter, bool needPatcher, int& patchIter) +Slice::JavaVisitor::writeUnmarshalDataMember(Output& out, const string& package, const DataMemberPtr& member, int& iter) { - string patchParams; - if(needPatcher) - { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(member->type()); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(member->type())) - { - ostringstream ostr; - ostr << "new Patcher(" << patchIter++ << ')'; - patchParams = ostr.str(); - } - } + // TBD: Handle passing interface-by-value - if(!member->optional()) - { - writeMarshalUnmarshalCode(out, package, member->type(), OptionalNone, false, 0, fixKwd(member->name()), false, - iter, false, member->getMetaData(), patchParams); - } - else + const string patchParams = getPatcher(member->type(), package, fixKwd(member->name()), false); + + if(member->optional()) { out << nl << "if(__has_" << member->name() << " = __is.readOptional(" << member->tag() << ", " << getOptionalFormat(member->type()) << "))"; out << sb; writeMarshalUnmarshalCode(out, package, member->type(), OptionalMember, false, 0, fixKwd(member->name()), false, - iter, false, member->getMetaData(), patchParams); + iter, member->getMetaData(), patchParams); out << eb; } + else + { + writeMarshalUnmarshalCode(out, package, member->type(), OptionalNone, false, 0, fixKwd(member->name()), false, + iter, member->getMetaData(), patchParams); + } } void -Slice::JavaVisitor::writePatcher(Output& out, const string& package, const DataMemberList& classMembers, - const DataMemberList& optionalMembers) +Slice::JavaVisitor::writeDispatch(Output& out, const ClassDefPtr& p) { - out << sp << nl << "private class Patcher implements Ice.ReadValueCallback"; - out << sb; - if(classMembers.size() > 1) + const string name = fixKwd(p->name()); + const string package = getPackage(p); + const string scoped = p->scoped(); + const ClassList bases = p->bases(); + ClassDefPtr base; + if(!bases.empty() && !bases.front()->isInterface()) { - out << sp << nl << "Patcher(int member)"; - out << sb; - out << nl << "__member = member;"; - out << eb; + base = bases.front(); } + const OperationList ops = p->operations(); - out << sp << nl << "public void" << nl << "valueReady(Ice.Object v)"; - out << sb; - if(classMembers.size() > 1) - { - out << nl << "switch(__member)"; - out << sb; - } - int memberCount = 0; - for(DataMemberList::const_iterator d = classMembers.begin(); d != classMembers.end(); ++d) + for(OperationList::const_iterator r = ops.begin(); r != ops.end(); ++r) { - if((*d)->optional()) - { - continue; - } - - BuiltinPtr b = BuiltinPtr::dynamicCast((*d)->type()); - if(b) - { - assert(b->kind() == Builtin::KindObject); - } + OperationPtr op = *r; - if(classMembers.size() > 1) - { - out.dec(); - out << nl << "case " << memberCount << ":"; - out.inc(); - if(b) - { - out << nl << "__typeId = Ice.ObjectImpl.ice_staticId();"; - } - else - { - out << nl << "__typeId = \"" << (*d)->type()->typeId() << "\";"; - } - } + vector<string> params = getParams(op, package); - string memberName = fixKwd((*d)->name()); - if(b) - { - out << nl << memberName << " = v;"; - } - else - { - string memberType = typeToString((*d)->type(), TypeModeMember, package); - out << nl << "if(v == null || v instanceof " << memberType << ")"; - out << sb; - out << nl << memberName << " = (" << memberType << ")v;"; - out << eb; - out << nl << "else"; - out << sb; - out << nl << "IceInternal.Ex.throwUOE(type(), v);"; - out << eb; - } + const bool amd = p->hasMetaData("amd") || op->hasMetaData("amd"); - if(classMembers.size() > 1) - { - out << nl << "break;"; - } + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); - memberCount++; - } + out << sp; - for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) - { - BuiltinPtr b = BuiltinPtr::dynamicCast((*d)->type()); - if(b && b->kind() != Builtin::KindObject) + const string deprecateReason = getDeprecateReason(op, p, "operation"); + const string currentParam = "@param __current The Current object for the invocation."; + if(amd) { - continue; + writeDocCommentAsync(out, op, InParam, currentParam); + out << nl << "java.util.concurrent.CompletionStage<" << getResultType(op, package, true, true) << "> " + << op->name() << "Async" << spar << params << "com.zeroc.Ice.Current __current" << epar; + writeThrowsClause(package, throws); + out << ';'; } - - TypePtr paramType = (*d)->type(); - BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) + else { - - if(classMembers.size() > 1) - { - out.dec(); - out << nl << "case " << memberCount << ":"; - out.inc(); - if(b) - { - out << nl << "__typeId = Ice.ObjectImpl.ice_staticId();"; - } - else - { - out << nl << "__typeId = \"" << (*d)->type()->typeId() << "\";"; - } - } - - string capName = (*d)->name(); - capName[0] = toupper(static_cast<unsigned char>(capName[0])); - - if(b) - { - out << nl << "set" << capName << "(v);"; - } - else - { - string memberType = typeToString((*d)->type(), TypeModeMember, package); - out << nl << "if(v == null || v instanceof " << memberType << ")"; - out << sb; - out << nl << "set" << capName << "((" << memberType << ")v);"; - out << eb; - out << nl << "else"; - out << sb; - out << nl << "IceInternal.Ex.throwUOE(type(), v);"; - out << eb; - } - - if(classMembers.size() > 1) - { - out << nl << "break;"; - } - - memberCount++; + writeDocComment(out, op, deprecateReason, currentParam); + out << nl << getResultType(op, package, false, true) << ' ' << fixKwd(op->name()) << spar << params + << "com.zeroc.Ice.Current __current" << epar; + writeThrowsClause(package, throws); + out << ';'; } } - if(classMembers.size() > 1) - { - out << eb; - } - out << eb; - - out << sp << nl << "public String" << nl << "type()"; - out << sb; - if(classMembers.size() > 1) - { - out << nl << "return __typeId;"; - } - else - { - out << nl << "return \"" << (*classMembers.begin())->type()->typeId() << "\";"; - } - out << eb; - - if(classMembers.size() > 1) - { - out << sp << nl << "private int __member;"; - out << nl << "private String __typeId;"; - } - - out << eb; -} - -void -Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& p) -{ - string name = fixKwd(p->name()); - string package = getPackage(p); - string scoped = p->scoped(); - ClassList bases = p->bases(); - ClassDefPtr base; - if(!bases.empty() && !bases.front()->isInterface()) - { - base = bases.front(); - } - ClassList allBases = p->allBases(); StringList ids; transform(allBases.begin(), allBases.end(), back_inserter(ids), constMemFun(&Contained::scoped)); @@ -1008,12 +971,10 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& other.sort(); ids.merge(other); ids.unique(); - StringList::const_iterator firstIter = ids.begin(); StringList::const_iterator scopedIter = find(ids.begin(), ids.end(), scoped); assert(scopedIter != ids.end()); - StringList::difference_type scopedPos = ::IceUtilInternal::distance(firstIter, scopedIter); - out << sp << nl << "public static final String[] __ids ="; + out << sp << nl << "static final String[] __ids ="; out << sb; for(StringList::const_iterator q = ids.begin(); q != ids.end();) @@ -1026,169 +987,34 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& } out << eb << ';'; - out << sp << nl << "public boolean ice_isA(String s)"; - out << sb; - out << nl << "return java.util.Arrays.binarySearch(__ids, s) >= 0;"; - out << eb; - - out << sp << nl << "public boolean ice_isA(String s, Ice.Current __current)"; - out << sb; - out << nl << "return java.util.Arrays.binarySearch(__ids, s) >= 0;"; - out << eb; - - out << sp << nl << "public String[] ice_ids()"; + out << sp << nl << "@Override" << nl << "default String[] ice_ids(com.zeroc.Ice.Current __current)"; out << sb; out << nl << "return __ids;"; out << eb; - out << sp << nl << "public String[] ice_ids(Ice.Current __current)"; - out << sb; - out << nl << "return __ids;"; - out << eb; - - out << sp << nl << "public String ice_id()"; - out << sb; - out << nl << "return __ids[" << scopedPos << "];"; - out << eb; - - out << sp << nl << "public String ice_id(Ice.Current __current)"; + out << sp << nl << "@Override" << nl << "default String ice_id(com.zeroc.Ice.Current __current)"; out << sb; - out << nl << "return __ids[" << scopedPos << "];"; + out << nl << "return ice_staticId();"; out << eb; - out << sp << nl << "public static String ice_staticId()"; + out << sp << nl; + out << "static String ice_staticId()"; out << sb; - out << nl << "return __ids[" << scopedPos << "];"; - out << eb; - - OperationList ops = p->allOperations(); - - // - // Write the "no Current" implementation of each operation. - // - for(OperationList::const_iterator r = ops.begin(); r != ops.end(); ++r) + if(p->isInterface()) { - OperationPtr op = *r; - string opName = op->name(); - - ContainerPtr container = op->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - assert(cl); - - string deprecateReason = getDeprecateReason(op, cl, "operation"); - - const bool amd = cl->hasMetaData("amd") || op->hasMetaData("amd"); - const bool optionalMapping = useOptionalMapping(op); - - vector<string> params; - vector<string> args; - TypePtr ret; - - if(amd) - { - opName += "_async"; - params = getParamsAsync(op, package, true, true); - args = getArgsAsync(op); - } - else - { - opName = fixKwd(opName); - ret = op->returnType(); - params = getParams(op, package, false, optionalMapping); - args = getArgs(op); - } - - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); - - // - // Only generate a "no current" version of the operation if it hasn't been done in a base - // class already, because the "no current" version is final. - // - bool generateOperation = cl == p; // Generate if the operation is defined in this class. - if(!generateOperation) - { - // - // The operation is not defined in this class. - // - if(!bases.empty()) - { - // - // Check if the operation is already implemented by a base class. - // - bool implementedByBase = false; - if(!bases.front()->isInterface()) - { - OperationList baseOps = bases.front()->allOperations(); - OperationList::const_iterator i; - for(i = baseOps.begin(); i != baseOps.end(); ++i) - { - if((*i)->name() == op->name()) - { - implementedByBase = true; - break; - } - } - if(i == baseOps.end()) - { - generateOperation = true; - } - } - if(!generateOperation && !implementedByBase) - { - // - // No base class defines the operation. Check if one of the - // interfaces defines it, in which case this class must provide it. - // - if(bases.front()->isInterface() || bases.size() > 1) - { - generateOperation = true; - } - } - } - } - if(generateOperation) - { - out << sp; - if(amd) - { - writeDocCommentAsync(out, op, InParam); - } - else - { - writeDocComment(out, op, deprecateReason); - } - out << nl << "public final " - << typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, - optionalMapping && op->returnIsOptional()) - << ' ' << opName << spar << params << epar; - if(op->hasMetaData("UserException")) - { - out.inc(); - out << nl << "throws Ice.UserException"; - out.dec(); - } - else - { - writeThrowsClause(package, throws); - } - out << sb << nl; - if(ret) - { - out << "return "; - } - out << opName << spar << args << "null" << epar << ';'; - out << eb; - } + out << nl << "return ice_staticId;"; } + else + { + out << nl << "return " << fixKwd(p->name()) << ".ice_staticId;"; + } + out << eb; // - // Dispatch operations. We only generate methods for operations + // Dispatch methods. We only generate methods for operations // defined in this ClassDef, because we reuse existing methods // for inherited operations. // - ops = p->operations(); for(OperationList::const_iterator r = ops.begin(); r != ops.end(); ++r) { OperationPtr op = *r; @@ -1204,76 +1030,62 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& { out << nl << "/** @deprecated **/"; } - out << nl << "public static Ice.DispatchStatus ___" << opName << '(' << name - << " __obj, IceInternal.Incoming __inS, Ice.Current __current)"; + out << nl; + out << "static java.util.concurrent.CompletionStage<com.zeroc.Ice.OutputStream> ___" << opName << '('; + if(p->isInterface()) + { + out << name; + } + else + { + out << '_' << p->name() << "Disp"; + } + out << " __obj, final com.zeroc.IceInternal.Incoming __inS, com.zeroc.Ice.Current __current)"; + if(!op->throws().empty()) + { + out.inc(); + out << nl << "throws com.zeroc.Ice.UserException"; + out.dec(); + } out << sb; const bool amd = cl->hasMetaData("amd") || op->hasMetaData("amd"); - const bool optionalMapping = useOptionalMapping(op); - if(!amd) - { - TypePtr ret = op->returnType(); + const TypePtr ret = op->returnType(); - ParamDeclList inParams; - ParamDeclList outParams; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) - { - if((*pli)->isOutParam()) - { - outParams.push_back(*pli); - } - else - { - inParams.push_back(*pli); - } - } + const ParamDeclList inParams = op->inParameters(); + const ParamDeclList outParams = op->outParameters(); - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); + out << nl << "com.zeroc.Ice.Object.__checkMode(" << sliceModeToIceMode(op->mode()) << ", __current.mode);"; + + if(!inParams.empty()) + { + ParamDeclList values; // - // Arrange exceptions into most-derived to least-derived order. If we don't - // do this, a base exception handler can appear before a derived exception - // handler, causing compiler warnings and resulting in the base exception - // being marshaled instead of the derived exception. + // Declare 'in' parameters. // -#if defined(__SUNPRO_CC) - throws.sort(Slice::derivedToBaseCompare); -#else - throws.sort(Slice::DerivedToBaseCompare()); -#endif - - int iter; - - out << nl << "__checkMode(" << sliceModeToIceMode(op->mode()) << ", __current.mode);"; - - if(!inParams.empty()) + out << nl << "com.zeroc.Ice.InputStream __is = __inS.startReadParams();"; + for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) { - // - // Unmarshal 'in' parameters. - // - out << nl << "Ice.InputStream __is = __inS.startReadParams();"; - for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) + const TypePtr paramType = (*pli)->type(); + if(isValue(paramType)) { - TypePtr paramType = (*pli)->type(); - string paramName = fixKwd((*pli)->name()); - string typeS = typeToString(paramType, TypeModeIn, package, (*pli)->getMetaData(), - true, (*pli)->optional()); + allocatePatcher(out, paramType, package, "__" + (*pli)->name()); + values.push_back(*pli); + } + else + { + const string paramName = fixKwd((*pli)->name()); + const string typeS = typeToString(paramType, TypeModeIn, package, (*pli)->getMetaData(), true, + (*pli)->optional()); if((*pli)->optional()) { - out << nl << typeS << ' ' << paramName << " = new " << typeS << "();"; + out << nl << typeS << ' ' << paramName << ';'; } else { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) - { - out << nl << typeS << "Holder " << paramName << " = new " << typeS << "Holder();"; - } - else if(StructPtr::dynamicCast(paramType)) + if(StructPtr::dynamicCast(paramType)) { out << nl << typeS << ' ' << paramName << " = null;"; } @@ -1283,199 +1095,115 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& } } } - iter = 0; - writeMarshalUnmarshalParams(out, package, inParams, 0, iter, false, true, true); - if(op->sendsClasses(false)) - { - out << nl << "__is.readPendingValues();"; - } - out << nl << "__inS.endReadParams();"; - } - else - { - out << nl << "__inS.readEmptyParams();"; } // - // Declare 'out' parameters. + // Unmarshal 'in' parameters. // - for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) + ParamDeclList required, optional; + op->inParameters(required, optional); + int iter = 0; + for(ParamDeclList::const_iterator pli = required.begin(); pli != required.end(); ++pli) { - string typeS = typeToString((*pli)->type(), TypeModeOut, package, (*pli)->getMetaData(), true, - optionalMapping && (*pli)->optional()); - out << nl << typeS << ' ' << fixKwd((*pli)->name()) << " = new " << typeS << "();"; + const string paramName = isValue((*pli)->type()) ? ("__" + (*pli)->name()) : fixKwd((*pli)->name()); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalNone, false, 0, paramName, false, + iter, (*pli)->getMetaData(), paramName); } - - // - // Call on the servant. - // - if(!throws.empty()) + for(ParamDeclList::const_iterator pli = optional.begin(); pli != optional.end(); ++pli) { - out << nl << "try"; - out << sb; + const string paramName = isValue((*pli)->type()) ? ("__" + (*pli)->name()) : fixKwd((*pli)->name()); + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalInParam, true, (*pli)->tag(), + paramName, false, iter, (*pli)->getMetaData(), paramName); } - out << nl; - if(ret) + if(op->sendsClasses(false)) { - string retS = typeToString(ret, TypeModeReturn, package, opMetaData, true, - optionalMapping && op->returnIsOptional()); - out << retS << " __ret = "; + out << nl << "__is.readPendingValues();"; } - out << "__obj." << fixKwd(opName) << '('; - for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) + out << nl << "__inS.endReadParams();"; + + for(ParamDeclList::const_iterator pli = values.begin(); pli != values.end(); ++pli) { - TypePtr paramType = (*pli)->type(); - out << fixKwd((*pli)->name()); - if(!(*pli)->optional()) + const TypePtr paramType = (*pli)->type(); + const string paramName = fixKwd((*pli)->name()); + const string typeS = typeToString(paramType, TypeModeIn, package, (*pli)->getMetaData(), true, + (*pli)->optional()); + if((*pli)->optional()) { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) - { - out << ".value"; - } + out << nl << typeS << ' ' << paramName << " = java.util.Optional.ofNullable(__" << (*pli)->name() + << ".value);"; } - out << ", "; - } - for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) - { - out << fixKwd((*pli)->name()) << ", "; - } - out << "__current);"; - - // - // Marshal 'out' parameters and return value. - // - if(!outParams.empty() || ret) - { - out << nl << "Ice.OutputStream __os = __inS.__startWriteParams(" - << opFormatTypeToString(op) << ");"; - writeMarshalUnmarshalParams(out, package, outParams, op, iter, true, optionalMapping, true); - if(op->returnsClasses(false)) + else { - out << nl << "__os.writePendingValues();"; + out << nl << typeS << ' ' << paramName << " = __" << (*pli)->name() << ".value;"; } - out << nl << "__inS.__endWriteParams(true);"; } - else + } + else + { + out << nl << "__inS.readEmptyParams();"; + } + + if(op->format() != DefaultFormat) + { + out << nl << "__inS.setFormat(" << opFormatTypeToString(op) << ");"; + } + + if(amd) + { + if(op->hasMarshaledResult()) { - out << nl << "__inS.__writeEmptyParams();"; + out << nl << "return __inS.setMarshaledResultFuture(__obj." << opName << "Async" << spar + << getInArgs(op) << "__current" << epar << ");"; } - out << nl << "return Ice.DispatchStatus.DispatchOK;"; - - // - // Handle user exceptions. - // - if(!throws.empty()) + else { - out << eb; - for(ExceptionList::const_iterator t = throws.begin(); t != throws.end(); ++t) + out << nl << "return __inS.setResultFuture(__obj." << opName << "Async" << spar << getInArgs(op) + << "__current" << epar; + if(ret || !outParams.empty()) { - string exS = getAbsolute(*t, package); - out << nl << "catch(" << exS << " ex)"; + out << ", (__os, __ret) ->"; + out.inc(); out << sb; - out << nl << "__inS.__writeUserException(ex, " << opFormatTypeToString(op) << ");"; - out << nl << "return Ice.DispatchStatus.DispatchUserException;"; + writeMarshalServantResults(out, package, op, "__ret"); out << eb; + out.dec(); } + out << ");"; } - - out << eb; } else { - ParamDeclList inParams; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + // + // Call on the servant. + // + out << nl; + if(ret || !outParams.empty()) { - if(!(*pli)->isOutParam()) - { - inParams.push_back(*pli); - } + out << getResultType(op, package, false, true) << " __ret = "; } + out << "__obj." << fixKwd(opName) << spar << getInArgs(op) << "__current" << epar << ';'; - int iter; - - out << nl << "__checkMode(" << sliceModeToIceMode(op->mode()) << ", __current.mode);"; - - if(!inParams.empty()) + // + // Marshal 'out' parameters and return value. + // + if(op->hasMarshaledResult()) { - // - // Unmarshal 'in' parameters. - // - out << nl << "Ice.InputStream __is = __inS.startReadParams();"; - iter = 0; - for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) - { - TypePtr paramType = (*pli)->type(); - string paramName = fixKwd((*pli)->name()); - string typeS = typeToString(paramType, TypeModeIn, package, (*pli)->getMetaData(), - true, (*pli)->optional()); - if((*pli)->optional()) - { - out << nl << typeS << ' ' << paramName << " = new " << typeS << "();"; - } - else - { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) - { - out << nl << typeS << "Holder " << paramName << " = new " << typeS << "Holder();"; - } - else if(StructPtr::dynamicCast(paramType)) - { - out << nl << typeS << ' ' << paramName << " = null;"; - } - else - { - out << nl << typeS << ' ' << paramName << ';'; - } - } - } - writeMarshalUnmarshalParams(out, package, inParams, 0, iter, false, true, true); - if(op->sendsClasses(false)) - { - out << nl << "__is.readPendingValues();"; - } - out << nl << "__inS.endReadParams();"; + out << nl << "return __inS.setMarshaledResult(__ret);"; } - else + else if(ret || !outParams.empty()) { - out << nl << "__inS.readEmptyParams();"; + out << nl << "com.zeroc.Ice.OutputStream __os = __inS.startWriteParams();"; + writeMarshalServantResults(out, package, op, "__ret"); + out << nl << "__inS.endWriteParams(__os);"; + out << nl << "return __inS.setResult(__os);"; } - - // - // Call on the servant. - // - string classNameAMD = "AMD_" + p->name(); - out << nl << classNameAMD << '_' << opName << " __cb = new _" << classNameAMD << '_' << opName - << "(__inS);"; - out << nl << "try"; - out << sb; - out << nl << "__obj." << (amd ? opName + "_async" : fixKwd(opName)) << (amd ? "(__cb, " : "("); - for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) + else { - TypePtr paramType = (*pli)->type(); - out << fixKwd((*pli)->name()); - if(!(*pli)->optional()) - { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); - if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) - { - out << ".value"; - } - } - out << ", "; + out << nl << "return __inS.setResult(__inS.writeEmptyParams());"; } - out << "__current);"; - out << eb; - out << nl << "catch(java.lang.Exception ex)"; - out << sb; - out << nl << "__cb.ice_exception(ex);"; - out << eb; - out << nl << "return Ice.DispatchStatus.DispatchAsync;"; - - out << eb; } + + out << eb; } OperationList allOps = p->allOperations(); @@ -1490,7 +1218,7 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& allOpNames.sort(); allOpNames.unique(); - out << sp << nl << "private final static String[] __all ="; + out << sp << nl << "final static String[] __ops ="; out << sb; for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end();) { @@ -1519,12 +1247,18 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& break; } } - out << nl << "public Ice.DispatchStatus __dispatch(IceInternal.Incoming in, Ice.Current __current)"; + out << nl << "@Override" << nl + << "default java.util.concurrent.CompletionStage<com.zeroc.Ice.OutputStream> __dispatch(" + << "com.zeroc.IceInternal.Incoming in, com.zeroc.Ice.Current __current)"; + out.inc(); + out << nl << "throws com.zeroc.Ice.UserException"; + out.dec(); out << sb; - out << nl << "int pos = java.util.Arrays.binarySearch(__all, __current.operation);"; + out << nl << "int pos = java.util.Arrays.binarySearch(__ops, __current.operation);"; out << nl << "if(pos < 0)"; out << sb; - out << nl << "throw new Ice.OperationNotExistException(__current.id, __current.facet, __current.operation);"; + out << nl << "throw new " + << "com.zeroc.Ice.OperationNotExistException(__current.id, __current.facet, __current.operation);"; out << eb; out << sp << nl << "switch(pos)"; out << sb; @@ -1537,19 +1271,19 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& out << sb; if(opName == "ice_id") { - out << nl << "return ___ice_id(this, in, __current);"; + out << nl << "return com.zeroc.Ice.Object.___ice_id(this, in, __current);"; } else if(opName == "ice_ids") { - out << nl << "return ___ice_ids(this, in, __current);"; + out << nl << "return com.zeroc.Ice.Object.___ice_ids(this, in, __current);"; } else if(opName == "ice_isA") { - out << nl << "return ___ice_isA(this, in, __current);"; + out << nl << "return com.zeroc.Ice.Object.___ice_isA(this, in, __current);"; } else if(opName == "ice_ping") { - out << nl << "return ___ice_ping(this, in, __current);"; + out << nl << "return com.zeroc.Ice.Object.___ice_ping(this, in, __current);"; } else { @@ -1572,11 +1306,11 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& string base; if(cl->isInterface()) { - base = getAbsolute(cl, package, "_", "Disp"); + base = getAbsolute(cl, package); } else { - base = getAbsolute(cl, package); + base = getAbsolute(cl, package, "_", "Disp"); } out << nl << "return " << base << ".___" << opName << "(this, in, __current);"; } @@ -1588,7 +1322,8 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& } out << eb; out << sp << nl << "assert(false);"; - out << nl << "throw new Ice.OperationNotExistException(__current.id, __current.facet, __current.operation);"; + out << nl << "throw new " + << "com.zeroc.Ice.OperationNotExistException(__current.id, __current.facet, __current.operation);"; out << eb; // @@ -1607,7 +1342,7 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& if(!attributesMap.empty()) { - out << sp << nl << "private final static int[] __operationAttributes ="; + out << sp << nl << "final static int[] __operationAttributes ="; out << sb; for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end();) { @@ -1627,9 +1362,9 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& } out << eb << ';'; - out << sp << nl << "public int ice_operationAttributes(String operation)"; + out << sp << nl << "@Override" << nl << "default int ice_operationAttributes(String operation)"; out << sb; - out << nl << "int pos = java.util.Arrays.binarySearch(__all, operation);"; + out << nl << "int pos = java.util.Arrays.binarySearch(__ops, operation);"; out << nl << "if(pos < 0)"; out << sb; out << nl << "return -1;"; @@ -1638,6 +1373,20 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& out << eb; } } +} + +void +Slice::JavaVisitor::writeMarshaling(Output& out, const ClassDefPtr& p) +{ + string name = fixKwd(p->name()); + string package = getPackage(p); + string scoped = p->scoped(); + ClassList bases = p->bases(); + ClassDefPtr base; + if(!bases.empty() && !bases.front()->isInterface()) + { + base = bases.front(); + } int iter; DataMemberList members = p->dataMembers(); @@ -1647,14 +1396,18 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& if(preserved && !basePreserved) { - out << sp << nl << "public void __write(Ice.OutputStream __os)"; + out << sp; + out << nl << "@Override"; + out << nl << "public void __write(com.zeroc.Ice.OutputStream __os)"; out << sb; out << nl << "__os.startValue(__slicedData);"; out << nl << "__writeImpl(__os);"; out << nl << "__os.endValue();"; out << eb; - out << sp << nl << "public void __read(Ice.InputStream __is)"; + out << sp; + out << nl << "@Override"; + out << nl << "public void __read(com.zeroc.Ice.InputStream __is)"; out << sb; out << nl << "__is.startValue();"; out << nl << "__readImpl(__is);"; @@ -1662,9 +1415,11 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& out << eb; } - out << sp << nl << "protected void __writeImpl(Ice.OutputStream __os)"; + out << sp; + out << nl << "@Override"; + out << nl << "protected void __writeImpl(com.zeroc.Ice.OutputStream __os)"; out << sb; - out << nl << "__os.startSlice(ice_staticId(), " << p->compactId() << (!base ? ", true" : ", false") << ");"; + out << nl << "__os.startSlice(ice_staticId, " << p->compactId() << (!base ? ", true" : ", false") << ");"; iter = 0; for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) { @@ -1687,29 +1442,25 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& DataMemberList classMembers = p->classDataMembers(); DataMemberList allClassMembers = p->allClassDataMembers(); - if(classMembers.size() != 0) - { - writePatcher(out, package, classMembers, optionalMembers); - } - - out << sp << nl << "protected void __readImpl(Ice.InputStream __is)"; + out << sp; + out << nl << "@Override"; + out << nl << "protected void __readImpl(com.zeroc.Ice.InputStream __is)"; out << sb; out << nl << "__is.startSlice();"; - int patchIter = 0; - const bool needCustomPatcher = classMembers.size() > 1; iter = 0; for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) { if(!(*d)->optional()) { - writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + writeUnmarshalDataMember(out, package, *d, iter); } } for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) { - writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + writeUnmarshalDataMember(out, package, *d, iter); } + out << nl << "__is.endSlice();"; if(base) { @@ -1719,7 +1470,7 @@ Slice::JavaVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& if(preserved && !basePreserved) { - out << sp << nl << "protected Ice.SlicedData __slicedData;"; + out << sp << nl << "protected com.zeroc.Ice.SlicedData __slicedData;"; } } @@ -1857,13 +1608,15 @@ Slice::JavaVisitor::writeConstantValue(Output& out, const TypePtr& type, const S out << "\\\""; } // - // Unicode character in the range U+10000 to U+10FFFF is not permitted in a character literal - // and is represented using a Unicode surrogate pair. + // Unicode character in the range U+10000 to U+10FFFF is not permitted in a + // character literal and is represented using a Unicode surrogate pair. // else if(v > 0xFFFF) { - unsigned int high = ((static_cast<unsigned int>(v) - 0x10000) / 0x400) + 0xD800; - unsigned int low = ((static_cast<unsigned int>(v) - 0x10000) % 0x400) + 0xDC00; + unsigned int high = + ((static_cast<unsigned int>(v) - 0x10000) / 0x400) + 0xD800; + unsigned int low = + ((static_cast<unsigned int>(v) - 0x10000) % 0x400) + 0xDC00; out << u16CodePoint(high); out << u16CodePoint(low); } @@ -2118,7 +1871,6 @@ Slice::JavaVisitor::writeDocCommentOp(Output& out, const OperationPtr& p) return; } - out << sp << nl << "/**"; // @@ -2300,7 +2052,7 @@ Slice::JavaVisitor::writeDocCommentAMI(Output& out, const OperationPtr& p, Param if(paramType == InParam) { - out << nl << " * @return The asynchronous result object."; + out << nl << " * @return A future for the completion of the request."; if(!deprecateReason.empty()) { out << nl << " * @deprecated " << deprecateReason; @@ -2424,9 +2176,6 @@ Slice::Gen::generate(const UnitPtr& p) { JavaGenerator::validateMetaData(p); - OpsVisitor opsVisitor(_dir); - p->visit(&opsVisitor, false); - PackageVisitor packageVisitor(_dir); p->visit(&packageVisitor, false); @@ -2436,9 +2185,6 @@ Slice::Gen::generate(const UnitPtr& p) CompactIdVisitor compactIdVisitor(_dir); p->visit(&compactIdVisitor, false); - HolderVisitor holderVisitor(_dir); - p->visit(&holderVisitor, false); - HelperVisitor helperVisitor(_dir); p->visit(&helperVisitor, false); @@ -2447,16 +2193,6 @@ Slice::Gen::generate(const UnitPtr& p) DispatcherVisitor dispatcherVisitor(_dir); p->visit(&dispatcherVisitor, false); - - AsyncVisitor asyncVisitor(_dir); - p->visit(&asyncVisitor, false); -} - -void -Slice::Gen::generateTie(const UnitPtr& p) -{ - TieVisitor tieVisitor(_dir); - p->visit(&tieVisitor, false); } void @@ -2467,13 +2203,6 @@ Slice::Gen::generateImpl(const UnitPtr& p) } void -Slice::Gen::generateImplTie(const UnitPtr& p) -{ - ImplTieVisitor implTieVisitor(_dir); - p->visit(&implTieVisitor, false); -} - -void Slice::Gen::writeChecksumClass(const string& checksumClass, const string& dir, const ChecksumMap& m) { // @@ -2508,7 +2237,7 @@ Slice::Gen::writeChecksumClass(const string& checksumClass, const string& dir, c out << sp << nl << "public static final java.util.Map<String, String> checksums;"; out << sp << nl << "static"; out << sb; - out << nl << "java.util.Map<String, String> map = new java.util.HashMap<String, String>();"; + out << nl << "java.util.Map<String, String> map = new java.util.HashMap<>();"; for(ChecksumMap::const_iterator p = m.begin(); p != m.end(); ++p) { out << nl << "map.put(\"" << p->first << "\", \""; @@ -2528,360 +2257,6 @@ Slice::Gen::writeChecksumClass(const string& checksumClass, const string& dir, c out << nl; } -Slice::Gen::OpsVisitor::OpsVisitor(const string& dir) : - JavaVisitor(dir) -{ -} - -bool -Slice::Gen::OpsVisitor::visitClassDefStart(const ClassDefPtr& p) -{ - // - // Don't generate an Operations interface for non-abstract classes - // - if(!p->isAbstract()) - { - return false; - } - - if(!p->isLocal()) - { - writeOperations(p, false); - } - writeOperations(p, true); - - return false; -} - -void -Slice::Gen::OpsVisitor::writeOperations(const ClassDefPtr& p, bool noCurrent) -{ - string name = p->name(); - ClassList bases = p->bases(); - string package = getPackage(p); - string opIntfName = "Operations"; - if(noCurrent || p->isLocal()) - { - opIntfName += "NC"; - } - string absolute = getAbsolute(p, "", "_", opIntfName); - - open(absolute, p->file()); - - Output& out = output(); - - // - // Generate the operations interface - // - out << sp; - writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); - out << nl << "public interface " << '_' << name << opIntfName; - if((bases.size() == 1 && bases.front()->isAbstract()) || bases.size() > 1) - { - out << " extends "; - out.useCurrentPosAsIndent(); - bool first = true; - for(ClassList::const_iterator q = bases.begin(); q != bases.end();) - { - if((*q)->isAbstract()) - { - if(!first) - { - out << ',' << nl; - } - else - { - first = false; - } - out << getAbsolute(*q, package, "_", opIntfName); - } - ++q; - } - out.restoreIndent(); - } - out << sb; - - OperationList ops = p->operations(); - for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) - { - OperationPtr op = *r; - ContainerPtr container = op->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - string opname = op->name(); - - TypePtr ret; - vector<string> params; - - const bool amd = !p->isLocal() && (cl->hasMetaData("amd") || op->hasMetaData("amd")); - const bool optionalMapping = useOptionalMapping(op); - - if(amd) - { - params = getParamsAsync(op, package, true, true); - } - else - { - params = getParams(op, package, false, optionalMapping); - ret = op->returnType(); - } - - string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, - optionalMapping && op->returnIsOptional()); - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); - out << sp; - - string deprecateReason = getDeprecateReason(*r, p, "operation"); - string extraCurrent; - if(!noCurrent && !p->isLocal()) - { - extraCurrent = "@param __current The Current object for the invocation."; - } - if(amd) - { - writeDocCommentAsync(out, *r, InParam, extraCurrent); - } - else - { - writeDocComment(out, *r, deprecateReason, extraCurrent); - } - out << nl << retS << ' ' << (amd ? opname + "_async" : fixKwd(opname)) << spar << params; - if(!noCurrent && !p->isLocal()) - { - out << "Ice.Current __current"; - } - out << epar; - if(op->hasMetaData("UserException")) - { - out.inc(); - out << nl << "throws Ice.UserException"; - out.dec(); - } - else - { - writeThrowsClause(package, throws); - } - out << ';'; - } - - out << eb; - - close(); -} - -Slice::Gen::TieVisitor::TieVisitor(const string& dir) : - JavaVisitor(dir) -{ -} - -bool -Slice::Gen::TieVisitor::visitClassDefStart(const ClassDefPtr& p) -{ - string name = p->name(); - ClassList bases = p->bases(); - string package = getPackage(p); - string absolute = getAbsolute(p, "", "_", "Tie"); - string opIntfName = "Operations"; - if(p->isLocal()) - { - opIntfName += "NC"; - } - - // - // Don't generate a TIE class for a non-abstract class - // - if(!p->isAbstract()) - { - return false; - } - - open(absolute, p->file()); - - Output& out = output(); - - // - // Generate the TIE class - // - out << sp << nl << "public class " << '_' << name << "Tie"; - if(p->isInterface()) - { - if(p->isLocal()) - { - out << " implements " << fixKwd(name) << ", Ice.TieBase"; - } - else - { - out << " extends " << '_' << name << "Disp implements Ice.TieBase"; - } - } - else - { - out << " extends " << fixKwd(name) << " implements Ice.TieBase"; - } - - out << sb; - - out << sp << nl << "public _" << name << "Tie()"; - out << sb; - out << eb; - - out << sp << nl << "public _" << name << "Tie(" << '_' << name << opIntfName << " delegate)"; - out << sb; - out << nl << "_ice_delegate = delegate;"; - out << eb; - - out << sp << nl << "public java.lang.Object ice_delegate()"; - out << sb; - out << nl << "return _ice_delegate;"; - out << eb; - - out << sp << nl << "public void ice_delegate(java.lang.Object delegate)"; - out << sb; - out << nl << "_ice_delegate = (_" << name << opIntfName << ")delegate;"; - out << eb; - - out << sp << nl << "public boolean equals(java.lang.Object rhs)"; - out << sb; - out << nl << "if(this == rhs)"; - out << sb; - out << nl << "return true;"; - out << eb; - out << nl << "if(!(rhs instanceof " << '_' << name << "Tie))"; - out << sb; - out << nl << "return false;"; - out << eb; - out << sp << nl << "return _ice_delegate.equals(((" << '_' << name << "Tie)rhs)._ice_delegate);"; - out << eb; - - out << sp << nl << "public int hashCode()"; - out << sb; - out << nl << "return _ice_delegate.hashCode();"; - out << eb; - - if(p->isLocal()) - { - out << sp << nl << "public _" << name << "Tie clone()"; - out.inc(); - out << nl << "throws java.lang.CloneNotSupportedException"; - out.dec(); - out << sb; - out << nl << "return (_" << name << "Tie)super.clone();"; - out << eb; - } - - OperationList ops = p->allOperations(); - for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) - { - ContainerPtr container = (*r)->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - const bool hasAMD = cl->hasMetaData("amd") || (*r)->hasMetaData("amd"); - const bool optionalMapping = useOptionalMapping(*r); - - string opName = hasAMD ? (*r)->name() + "_async" : fixKwd((*r)->name()); - - TypePtr ret = (*r)->returnType(); - string retS = typeToString(ret, TypeModeReturn, package, (*r)->getMetaData(), true, - optionalMapping && (*r)->returnIsOptional()); - - vector<string> params; - vector<string> args; - if(hasAMD) - { - params = getParamsAsync((*r), package, true, true); - args = getArgsAsync(*r); - } - else - { - params = getParams((*r), package, false, optionalMapping); - args = getArgs(*r); - } - - string deprecateReason = getDeprecateReason(*r, cl, "operation"); - - out << sp; - if(!deprecateReason.empty()) - { - out << nl << "@Deprecated"; - out << nl << "@SuppressWarnings(\"deprecation\")"; - } - out << nl << "public " << (hasAMD ? string("void") : retS) << ' ' << opName << spar << params; - if(!p->isLocal()) - { - out << "Ice.Current __current"; - } - out << epar; - - if((*r)->hasMetaData("UserException")) - { - out.inc(); - out << nl << "throws Ice.UserException"; - out.dec(); - } - else - { - ExceptionList throws = (*r)->throws(); - throws.sort(); - throws.unique(); - writeThrowsClause(package, throws); - } - out << sb; - out << nl; - if(ret && !hasAMD) - { - out << "return "; - } - out << "_ice_delegate." << opName << spar << args; - if(!p->isLocal()) - { - out << "__current"; - } - out << epar << ';'; - out << eb; - } - - out << sp << nl << "private " << '_' << name << opIntfName << " _ice_delegate;"; - out << sp << nl << "public static final long serialVersionUID = "; - string serialVersionUID; - if(p->findMetaData("java:serialVersionUID", serialVersionUID)) - { - string::size_type pos = serialVersionUID.rfind(":") + 1; - if(pos == string::npos) - { - ostringstream os; - os << "ignoring invalid serialVersionUID for class `" << p->scoped() << "'; generating default value"; - emitWarning("", "", os.str()); - out << computeSerialVersionUUID(p); - } - else - { - Int64 v = 0; - serialVersionUID = serialVersionUID.substr(pos); - if(serialVersionUID != "0") - { - if(!stringToInt64(serialVersionUID, v)) // conversion error - { - ostringstream os; - os << "ignoring invalid serialVersionUID for class `" << p->scoped() - << "'; generating default value"; - emitWarning("", "", os.str()); - out << computeSerialVersionUUID(p); - } - } - out << v; - } - } - else - { - out << computeSerialVersionUUID(p); - } - out << "L;"; - out << eb; - close(); - - return false; -} - Slice::Gen::PackageVisitor::PackageVisitor(const string& dir) : JavaVisitor(dir) { @@ -2944,9 +2319,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) { out << " extends "; out.useCurrentPosAsIndent(); - out << "Ice.Object"; - out << "," << nl << '_' << name; - out << "Operations, _" << name << "OperationsNC"; + out << "com.zeroc.Ice.Object"; } else { @@ -2972,7 +2345,7 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) else { out << nl << "public "; - if(p->allOperations().size() > 0) // Don't use isAbstract() - see bug 3739 + if(p->isLocal() && !p->allOperations().empty()) { out << "abstract "; } @@ -2980,18 +2353,16 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) out.useCurrentPosAsIndent(); StringList implements; - bool implementsOnNewLine = true; if(bases.empty() || bases.front()->isInterface()) { if(p->isLocal()) { - implementsOnNewLine = false; - implements.push_back("java.lang.Cloneable"); + implements.push_back("java.lang.Cloneable"); } else { - out << " extends Ice.ObjectImpl"; + out << " extends com.zeroc.Ice.Value"; } } else @@ -3001,161 +2372,11 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) bases.pop_front(); } - // - // Implement interfaces - // - - if(p->isAbstract()) - { - if(!p->isLocal()) - { - implements.push_back("_" + name + "Operations"); - implements.push_back("_" + name + "OperationsNC"); - } - } - if(!bases.empty()) - { - for(ClassList::const_iterator q = bases.begin(); q != bases.end();) - { - implements.push_back(getAbsolute(*q, package)); - q++; - } - } - - if(!implements.empty()) - { - if(implementsOnNewLine) - { - out << nl; - } - - out << " implements "; - out.useCurrentPosAsIndent(); - - for(StringList::const_iterator q = implements.begin(); q != implements.end();) - { - if(q != implements.begin()) - { - out << ',' << nl; - } - out << *q; - q++; - } - - out.restoreIndent(); - } - out.restoreIndent(); } out << sb; - // - // For local classes and interfaces, we don't use the OperationsNC interface. - // Instead, we generate the operation signatures directly into the class - // or interface. - // - if(p->isLocal()) - { - OperationList ops = p->operations(); - for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) - { - OperationPtr op = *r; - const ContainerPtr container = op->container(); - const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - const string opname = op->name(); - const bool optionalMapping = useOptionalMapping(op); - - const TypePtr ret = op->returnType(); - vector<string> params = getParams(op, package, true, optionalMapping); - - string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, - optionalMapping && op->returnIsOptional()); - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); - out << sp; - - writeDocComment(out, *r, getDeprecateReason(*r, p, "operation")); - out << nl; - if(!p->isInterface()) - { - out << "public abstract "; - } - out << retS << ' ' << fixKwd(opname) << spar << params << epar; - if(op->hasMetaData("UserException")) - { - out.inc(); - out << nl << "throws Ice.UserException"; - out.dec(); - } - else - { - writeThrowsClause(package, throws); - } - out << ';'; - - // - // Generate asynchronous API for local operations marked with "async-oneway" metadata. - // - if(p->hasMetaData("async-oneway") || op->hasMetaData("async-oneway")) - { - vector<string> inParams = getInOutParams(op, package, InParam, true, true); - - out << sp; - writeDocCommentAMI(out, op, InParam); - out << nl; - if(!p->isInterface()) - { - out << "public abstract "; - } - out << "Ice.AsyncResult begin_" << opname << spar << inParams << epar << ';'; - - out << sp; - writeDocCommentAMI(out, op, InParam); - out << nl; - if(!p->isInterface()) - { - out << "public abstract "; - } - out << "Ice.AsyncResult begin_" << opname << spar << inParams << "Ice.Callback __cb" << epar << ';'; - - out << sp; - writeDocCommentAMI(out, op, InParam); - out << nl; - if(!p->isInterface()) - { - out << "public abstract "; - } - string cb = "Callback_" + name + "_" + opname + " __cb"; - out << "Ice.AsyncResult begin_" << opname << spar << inParams << cb << epar << ';'; - - - out << sp; - writeDocCommentAMI(out, op, InParam); - out << nl; - if(!p->isInterface()) - { - out << "public abstract "; - } - out << nl << "Ice.AsyncResult begin_" << opname; - writeParamList(out, getParamsAsyncLambda(op, package, false, true)); - out << ';'; - - vector<string> outParams = getInOutParams(op, package, OutParam, true, true); - out << sp; - writeDocCommentAMI(out, op, OutParam); - out << nl; - if(!p->isInterface()) - { - out << "public abstract "; - } - - out << retS << " end_" << opname << spar << outParams << "Ice.AsyncResult __result" << epar << ';'; - } - } - } - if(!p->isInterface() && !allDataMembers.empty()) { bool hasOptionalMembers = false; @@ -3294,36 +2515,6 @@ Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) } } - // - // Default factory for non-abstract classes. - // - if(!p->isInterface() && p->allOperations().size() == 0 && !p->isLocal()) - { - out << sp; - out << nl << "private static class __F implements Ice.ValueFactory"; - out << sb; - out << nl << "public Ice.Object create(String type)"; - out << sb; - out << nl << "assert(type.equals(ice_staticId()));"; - out << nl << "return new " << fixKwd(name) << "();"; - out << eb; - out << eb; - out << nl << "private static Ice.ValueFactory _factory = new __F();"; - out << sp; - out << nl << "public static Ice.ValueFactory" << nl << "ice_factory()"; - out << sb; - out << nl << "return _factory;"; - out << eb; - } - - // - // Marshalling & dispatch support. - // - if(!p->isInterface() && !p->isLocal()) - { - writeDispatchAndMarshalling(out, p); - } - return true; } @@ -3343,7 +2534,7 @@ Slice::Gen::TypesVisitor::visitClassDefEnd(const ClassDefPtr& p) if(!p->isInterface()) { - out << sp << nl << "public " << name << nl << "clone()"; + out << sp << nl << "public " << name << " clone()"; out << sb; if(p->isLocal() && !baseClass) @@ -3367,50 +2558,160 @@ Slice::Gen::TypesVisitor::visitClassDefEnd(const ClassDefPtr& p) out << eb; } - if(p->isInterface() && !p->isLocal()) + if(!p->isLocal()) { - out << sp << nl << "public static final String ice_staticId = \"" << p->scoped() << "\";"; - } + out << sp << nl; + if(!p->isInterface()) + { + out << "public "; + } + out << "static final String ice_staticId = \"" << p->scoped() << "\";"; - out << sp << nl << "public static final long serialVersionUID = "; - string serialVersionUID; - if(p->findMetaData("java:serialVersionUID", serialVersionUID)) - { - string::size_type pos = serialVersionUID.rfind(":") + 1; - if(pos == string::npos) + if(!p->isInterface()) { - ostringstream os; - os << "ignoring invalid serialVersionUID for class `" << p->scoped() << "'; generating default value"; - emitWarning("", "", os.str()); - out << computeSerialVersionUUID(p); + out << sp << nl << "public static String ice_staticId()"; + out << sb; + out << nl << "return ice_staticId;"; + out << eb; + + out << sp << nl << "@Override"; + out << nl << "public String ice_id()"; + out << sb; + out << nl << "return ice_staticId;"; + out << eb; } - else + } + + if(!p->isInterface()) + { + out << sp << nl << "public static final long serialVersionUID = "; + string serialVersionUID; + if(p->findMetaData("java:serialVersionUID", serialVersionUID)) { - Int64 v = 0; - serialVersionUID = serialVersionUID.substr(pos); - if(serialVersionUID != "0") + string::size_type pos = serialVersionUID.rfind(":") + 1; + if(pos == string::npos) { - if(!stringToInt64(serialVersionUID, v)) // conversion error + ostringstream os; + os << "ignoring invalid serialVersionUID for class `" << p->scoped() << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + else + { + Int64 v = 0; + serialVersionUID = serialVersionUID.substr(pos); + if(serialVersionUID != "0") { - ostringstream os; - os << "ignoring invalid serialVersionUID for class `" << p->scoped() - << "'; generating default value"; - emitWarning("", "", os.str()); - out << computeSerialVersionUUID(p); + if(!stringToInt64(serialVersionUID, v)) // conversion error + { + ostringstream os; + os << "ignoring invalid serialVersionUID for class `" << p->scoped() + << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } } + out << v; } - out << v; } + else + { + out << computeSerialVersionUUID(p); + } + out << "L;"; } - else + + if(!p->isLocal()) { - out << computeSerialVersionUUID(p); + if(p->isInterface()) + { + writeDispatch(out, p); + } + else + { + writeMarshaling(out, p); + } } - out << "L;"; + out << eb; close(); } +void +Slice::Gen::TypesVisitor::visitOperation(const OperationPtr& p) +{ + // + // Generate the operation signature for a servant. + // + + ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container()); + assert(cl); + + const string package = getPackage(cl); + + Output& out = output(); + + // + // Generate the "Result" type needed by operations that return multiple values. + // + if(p->returnsMultipleValues()) + { + writeResultType(out, p, package); + } + + if(p->hasMarshaledResult()) + { + writeMarshaledResultType(out, p, package); + } + + if(cl->isLocal()) + { + const string opname = p->name(); + vector<string> params = getParams(p, package); + + const string retS = getResultType(p, package, false, false); + + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); + out << sp; + + writeDocComment(out, p, getDeprecateReason(p, cl, "operation")); + out << nl; + if(!cl->isInterface()) + { + out << "public abstract "; + } + out << retS << ' ' << fixKwd(opname) << spar << params << epar; + if(p->hasMetaData("UserException")) + { + out.inc(); + out << nl << "throws com.zeroc.Ice.UserException"; + out.dec(); + } + else + { + writeThrowsClause(package, throws); + } + out << ';'; + + // + // Generate asynchronous API for local operations marked with "async-oneway" metadata. + // + if(cl->hasMetaData("async-oneway") || p->hasMetaData("async-oneway")) + { + out << sp; + writeDocCommentAMI(out, p, InParam); + out << nl; + if(!cl->isInterface()) + { + out << "public abstract "; + } + out << getFutureType(p, package) << ' ' << opname << "Async" << spar << params << epar << ';'; + } + } +} + bool Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) { @@ -3436,11 +2737,11 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) { if(p->isLocal()) { - out << "Ice.LocalException"; + out << "com.zeroc.Ice.LocalException"; } else { - out << "Ice.UserException"; + out << "com.zeroc.Ice.UserException"; } } else @@ -3520,7 +2821,8 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) if(!(*d)->optional()) { string memberName = fixKwd((*d)->name()); - string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData(), + true, false, p->isLocal()); paramDecl.push_back(memberType + " " + memberName); } } @@ -3599,7 +2901,8 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) for(DataMemberList::const_iterator d = allDataMembers.begin(); d != allDataMembers.end(); ++d) { string memberName = fixKwd((*d)->name()); - string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData(), true, + false, p->isLocal()); paramDecl.push_back(memberType + " " + memberName); } out << paramDecl << epar; @@ -3676,7 +2979,7 @@ Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) } } - out << sp << nl << "public String" << nl << "ice_id()"; + out << sp << nl << "public String ice_id()"; out << sb; out << nl << "return \"" << scoped << "\";"; out << eb; @@ -3704,15 +3007,18 @@ Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) if(preserved && !basePreserved) { - - out << sp << nl << "public void" << nl << "__write(Ice.OutputStream __os)"; + out << sp; + out << nl << "@Override"; + out << nl << "public void __write(com.zeroc.Ice.OutputStream __os)"; out << sb; out << nl << "__os.startException(__slicedData);"; out << nl << "__writeImpl(__os);"; out << nl << "__os.endException();"; out << eb; - out << sp << nl << "public void" << nl << "__read(Ice.InputStream __is)"; + out << sp; + out << nl << "@Override"; + out << nl << "public void __read(com.zeroc.Ice.InputStream __is)"; out << sb; out << nl << "__is.startException();"; out << nl << "__readImpl(__is);"; @@ -3720,7 +3026,9 @@ Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) out << eb; } - out << sp << nl << "protected void" << nl << "__writeImpl(Ice.OutputStream __os)"; + out << sp; + out << nl << "@Override"; + out << nl << "protected void __writeImpl(com.zeroc.Ice.OutputStream __os)"; out << sb; out << nl << "__os.startSlice(\"" << scoped << "\", -1, " << (!base ? "true" : "false") << ");"; iter = 0; @@ -3745,26 +3053,22 @@ Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) DataMemberList classMembers = p->classDataMembers(); DataMemberList allClassMembers = p->allClassDataMembers(); - if(classMembers.size() != 0) - { - writePatcher(out, package, classMembers, optionalMembers); - } - out << sp << nl << "protected void" << nl << "__readImpl(Ice.InputStream __is)"; + out << sp; + out << nl << "@Override"; + out << nl << "protected void __readImpl(com.zeroc.Ice.InputStream __is)"; out << sb; out << nl << "__is.startSlice();"; iter = 0; - int patchIter = 0; - const bool needCustomPatcher = classMembers.size() > 1; for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) { if(!(*d)->optional()) { - writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + writeUnmarshalDataMember(out, package, *d, iter); } } for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) { - writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + writeUnmarshalDataMember(out, package, *d, iter); } out << nl << "__is.endSlice();"; if(base) @@ -3777,7 +3081,9 @@ Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) { if(!base || (base && !base->usesClasses(false))) { - out << sp << nl << "public boolean" << nl << "__usesClasses()"; + out << sp; + out << nl << "@Override"; + out << nl << "public boolean __usesClasses()"; out << sb; out << nl << "return true;"; out << eb; @@ -3786,7 +3092,7 @@ Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) if(preserved && !basePreserved) { - out << sp << nl << "protected Ice.SlicedData __slicedData;"; + out << sp << nl << "protected com.zeroc.Ice.SlicedData __slicedData;"; } } @@ -3882,7 +3188,8 @@ Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) { string memberName = fixKwd((*d)->name()); - string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData(), true, false, + p->isLocal()); paramDecl.push_back(memberType + " " + memberName); paramNames.push_back(memberName); } @@ -3896,7 +3203,7 @@ Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) out << eb; } - out << sp << nl << "public boolean" << nl << "equals(java.lang.Object rhs)"; + out << sp << nl << "public boolean equals(java.lang.Object rhs)"; out << sb; out << nl << "if(this == rhs)"; out << sb; @@ -4003,20 +3310,20 @@ Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) out << sp << nl << "return false;"; out << eb; - out << sp << nl << "public int" << nl << "hashCode()"; + out << sp << nl << "public int hashCode()"; out << sb; out << nl << "int __h = 5381;"; - out << nl << "__h = IceInternal.HashUtil.hashAdd(__h, \"" << p->scoped() << "\");"; + out << nl << "__h = com.zeroc.IceInternal.HashUtil.hashAdd(__h, \"" << p->scoped() << "\");"; iter = 0; for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) { string memberName = fixKwd((*d)->name()); - out << nl << "__h = IceInternal.HashUtil.hashAdd(__h, " << memberName << ");"; + out << nl << "__h = com.zeroc.IceInternal.HashUtil.hashAdd(__h, " << memberName << ");"; } out << nl << "return __h;"; out << eb; - out << sp << nl << "public " << name << nl << "clone()"; + out << sp << nl << "public " << name << " clone()"; out << sb; out << nl << name << " c = null;"; out << nl << "try"; @@ -4032,7 +3339,7 @@ Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) if(!p->isLocal()) { - out << sp << nl << "public void" << nl << "__write(Ice.OutputStream __os)"; + out << sp << nl << "public void ice_write(com.zeroc.Ice.OutputStream __os)"; out << sb; iter = 0; for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) @@ -4043,41 +3350,34 @@ Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) DataMemberList classMembers = p->classDataMembers(); - if(classMembers.size() != 0) - { - writePatcher(out, package, classMembers, DataMemberList()); - } - - out << sp << nl << "public void" << nl << "__read(Ice.InputStream __is)"; + out << sp << nl << "public void ice_read(com.zeroc.Ice.InputStream __is)"; out << sb; iter = 0; - int patchIter = 0; - const bool needCustomPatcher = classMembers.size() > 1; for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) { - writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + writeUnmarshalDataMember(out, package, *d, iter); } out << eb; - out << sp << nl << "static public void" << nl << "write(Ice.OutputStream __os, " << name << " __v)"; + out << sp << nl << "static public void write(com.zeroc.Ice.OutputStream __os, " << name << " __v)"; out << sb; out << nl << "if(__v == null)"; out << sb; - out << nl << "__nullMarshalValue.__write(__os);"; + out << nl << "__nullMarshalValue.ice_write(__os);"; out << eb; out << nl << "else"; out << sb; - out << nl << "__v.__write(__os);"; + out << nl << "__v.ice_write(__os);"; out << eb; out << eb; - out << sp << nl << "static public " << name << nl << "read(Ice.InputStream __is, " << name << " __v)"; + out << sp << nl << "static public " << name << " read(com.zeroc.Ice.InputStream __is, " << name << " __v)"; out << sb; out << nl << "if(__v == null)"; out << sb; out << nl << " __v = new " << name << "();"; out << eb; - out << nl << "__v.__read(__is);"; + out << nl << "__v.ice_read(__is);"; out << nl << "return __v;"; out << eb; @@ -4127,15 +3427,38 @@ Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) void Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) { - string name = fixKwd(p->name()); - ContainerPtr container = p->container(); - ContainedPtr contained = ContainedPtr::dynamicCast(container); - StringList metaData = p->getMetaData(); - TypePtr type = p->type(); - string s = typeToString(type, TypeModeMember, getPackage(contained), metaData); - Output& out = output(); - const bool optional = p->optional(); + const ContainerPtr container = p->container(); + const ClassDefPtr cls = ClassDefPtr::dynamicCast(container); + const StructPtr st = StructPtr::dynamicCast(container); + const ExceptionPtr ex = ExceptionPtr::dynamicCast(container); + const ContainedPtr contained = ContainedPtr::dynamicCast(container); + + const string name = fixKwd(p->name()); + const StringList metaData = p->getMetaData(); const bool getSet = p->hasMetaData(_getSetMetaData) || contained->hasMetaData(_getSetMetaData); + const bool optional = p->optional(); + const TypePtr type = p->type(); + const BuiltinPtr b = BuiltinPtr::dynamicCast(type); + const bool classType = isValue(type); + + bool local; + if(cls) + { + local = cls->isLocal(); + } + else if(st) + { + local = st->isLocal(); + } + else + { + assert(ex); + local = ex->isLocal(); + } + + const string s = typeToString(type, TypeModeMember, getPackage(contained), metaData, true, false, local); + + Output& out = output(); out << sp; @@ -4146,8 +3469,7 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) // Access visibility for class data members can be controlled by metadata. // If none is specified, the default is public. // - if(contained->containedType() == Contained::ContainedTypeClass && - (p->hasMetaData("protected") || contained->hasMetaData("protected"))) + if(cls && (p->hasMetaData("protected") || contained->hasMetaData("protected"))) { out << nl << "protected " << s << ' ' << name << ';'; } @@ -4178,7 +3500,6 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) // OperationList ops; string file, line; - ClassDefPtr cls = ClassDefPtr::dynamicCast(container); if(cls) { ops = cls->allOperations(); @@ -4203,14 +3524,13 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) // out << sp; writeDocComment(out, p, deprecateReason); - out << nl << "public " << s - << nl << "get" << capName << "()"; + out << nl << "public " << s << " get" << capName << "()"; out << sb; if(optional) { out << nl << "if(!__has_" << p->name() << ')'; out << sb; - out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << nl << "throw new java.util.NoSuchElementException(\"" << name << " is not set\");"; out << eb; } out << nl << "return " << name << ';'; @@ -4221,8 +3541,7 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) // out << sp; writeDocComment(out, p, deprecateReason); - out << nl << "public void" - << nl << "set" << capName << '(' << s << " _" << name << ')'; + out << nl << "public void set" << capName << '(' << s << " _" << name << ')'; out << sb; if(optional) { @@ -4238,50 +3557,96 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) { out << sp; writeDocComment(out, p, deprecateReason); - out << nl << "public boolean" - << nl << "has" << capName << "()"; + out << nl << "public boolean has" << capName << "()"; out << sb; out << nl << "return __has_" << p->name() << ';'; out << eb; out << sp; writeDocComment(out, p, deprecateReason); - out << nl << "public void" - << nl << "clear" << capName << "()"; + out << nl << "public void clear" << capName << "()"; out << sb; out << nl << "__has_" << p->name() << " = false;"; out << eb; - const string optType = typeToString(type, TypeModeMember, getPackage(contained), metaData, true, true); + const string optType = + typeToString(type, TypeModeMember, getPackage(contained), metaData, true, true, local); out << sp; writeDocComment(out, p, deprecateReason); - out << nl << "public void" - << nl << "optional" << capName << '(' << optType << " __v)"; + out << nl << "public void optional" << capName << '(' << optType << " __v)"; out << sb; - out << nl << "if(__v == null || !__v.isSet())"; + out << nl << "if(__v == null || !__v.isPresent())"; out << sb; out << nl << "__has_" << p->name() << " = false;"; out << eb; out << nl << "else"; out << sb; out << nl << "__has_" << p->name() << " = true;"; - out << nl << name << " = __v.get();"; + if(b && b->kind() == Builtin::KindInt) + { + out << nl << name << " = __v.getAsInt();"; + } + else if(b && b->kind() == Builtin::KindLong) + { + out << nl << name << " = __v.getAsLong();"; + } + else if(b && b->kind() == Builtin::KindDouble) + { + out << nl << name << " = __v.getAsDouble();"; + } + else + { + out << nl << name << " = __v.get();"; + } out << eb; out << eb; out << sp; writeDocComment(out, p, deprecateReason); - out << nl << "public " << optType - << nl << "optional" << capName << "()"; + out << nl << "public " << optType << " optional" << capName << "()"; out << sb; out << nl << "if(__has_" << p->name() << ')'; out << sb; - out << nl << "return new " << optType << '(' << name << ");"; + if(classType) + { + out << nl << "return java.util.Optional.ofNullable(" << name << ");"; + } + else if(b && b->kind() == Builtin::KindInt) + { + out << nl << "return java.util.OptionalInt.of(" << name << ");"; + } + else if(b && b->kind() == Builtin::KindLong) + { + out << nl << "return java.util.OptionalLong.of(" << name << ");"; + } + else if(b && b->kind() == Builtin::KindDouble) + { + out << nl << "return java.util.OptionalDouble.of(" << name << ");"; + } + else + { + out << nl << "return java.util.Optional.of(" << name << ");"; + } out << eb; out << nl << "else"; out << sb; - out << nl << "return new " << optType << "();"; + if(b && b->kind() == Builtin::KindInt) + { + out << nl << "return java.util.OptionalInt.empty();"; + } + else if(b && b->kind() == Builtin::KindLong) + { + out << nl << "return java.util.OptionalLong.empty();"; + } + else if(b && b->kind() == Builtin::KindDouble) + { + out << nl << "return java.util.OptionalDouble.empty();"; + } + else + { + out << nl << "return java.util.Optional.empty();"; + } out << eb; out << eb; } @@ -4289,7 +3654,6 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) // // Check for bool type. // - BuiltinPtr b = BuiltinPtr::dynamicCast(type); if(b && b->kind() == Builtin::KindBool) { if(cls && !validateMethod(ops, "is" + capName, 0, file, line)) @@ -4303,14 +3667,13 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) out << nl << " * @deprecated " << deprecateReason; out << nl << " **/"; } - out << nl << "public boolean"; - out << nl << "is" << capName << "()"; + out << nl << "public boolean is" << capName << "()"; out << sb; if(optional) { out << nl << "if(!__has_" << p->name() << ')'; out << sb; - out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << nl << "throw new java.util.NoSuchElementException(\"" << name << " is not set\");"; out << eb; } out << nl << "return " << name << ';'; @@ -4332,7 +3695,8 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) return; } - string elem = typeToString(seq->type(), TypeModeMember, getPackage(contained)); + string elem = typeToString(seq->type(), TypeModeMember, getPackage(contained), StringList(), true, + false, local); // // Indexed getter. @@ -4344,14 +3708,13 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) out << nl << " * @deprecated " << deprecateReason; out << nl << " **/"; } - out << nl << "public " << elem; - out << nl << "get" << capName << "(int _index)"; + out << nl << "public " << elem << " get" << capName << "(int _index)"; out << sb; if(optional) { out << nl << "if(!__has_" << p->name() << ')'; out << sb; - out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << nl << "throw new java.util.NoSuchElementException(\"" << name << " is not set\");"; out << eb; } out << nl << "return " << name << "[_index];"; @@ -4367,14 +3730,13 @@ Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) out << nl << " * @deprecated " << deprecateReason; out << nl << " **/"; } - out << nl << "public void"; - out << nl << "set" << capName << "(int _index, " << elem << " _val)"; + out << nl << "public void set" << capName << "(int _index, " << elem << " _val)"; out << sb; if(optional) { out << nl << "if(!__has_" << p->name() << ')'; out << sb; - out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << nl << "throw new java.util.NoSuchElementException(\"" << name << " is not set\");"; out << eb; } out << nl << name << "[_index] = _val;"; @@ -4418,14 +3780,12 @@ Slice::Gen::TypesVisitor::visitEnum(const EnumPtr& p) } out << ';'; - out << sp << nl << "public int" - << nl << "value()"; + out << sp << nl << "public int value()"; out << sb; out << nl << "return __value;"; out << eb; - out << sp << nl << "public static " << name - << nl << "valueOf(int __v)"; + out << sp << nl << "public static " << name << " valueOf(int __v)"; out << sb; out << nl << "switch(__v)"; out << sb; @@ -4450,12 +3810,12 @@ Slice::Gen::TypesVisitor::visitEnum(const EnumPtr& p) if(!p->isLocal()) { - out << sp << nl << "public void" << nl << "__write(Ice.OutputStream __os)"; + out << sp << nl << "public void" << nl << "ice_write(com.zeroc.Ice.OutputStream __os)"; out << sb; out << nl << "__os.writeEnum(value(), " << p->maxValue() << ");"; out << eb; - out << sp << nl << "public static void" << nl << "write(Ice.OutputStream __os, " << name << " __v)"; + out << sp << nl << "public static void write(com.zeroc.Ice.OutputStream __os, " << name << " __v)"; out << sb; out << nl << "if(__v == null)"; out << sb; @@ -4468,19 +3828,18 @@ Slice::Gen::TypesVisitor::visitEnum(const EnumPtr& p) out << eb; out << eb; - out << sp << nl << "public static " << name << nl << "read(Ice.InputStream __is)"; + out << sp << nl << "public static " << name << " read(com.zeroc.Ice.InputStream __is)"; out << sb; out << nl << "int __v = __is.readEnum(" << p->maxValue() << ");"; out << nl << "return __validate(__v);"; out << eb; - out << sp << nl << "private static " << name - << nl << "__validate(int __v)"; + out << sp << nl << "private static " << name << " __validate(int __v)"; out << sb; out << nl << "final " << name << " __e = valueOf(__v);"; out << nl << "if(__e == null)"; out << sb; - out << nl << "throw new Ice.MarshalException(\"enumerator value \" + __v + \" is out of range\");"; + out << nl << "throw new com.zeroc.Ice.MarshalException(\"enumerator value \" + __v + \" is out of range\");"; out << eb; out << nl << "return __e;"; out << eb; @@ -4552,7 +3911,7 @@ Slice::Gen::CompactIdVisitor::visitClassDefStart(const ClassDefPtr& p) if(p->compactId() >= 0) { ostringstream os; - os << prefix << "IceCompactId.TypeId_" << p->compactId(); + os << prefix << "com.zeroc.IceCompactId.TypeId_" << p->compactId(); open(os.str(), p->file()); Output& out = output(); @@ -4566,553 +3925,11 @@ Slice::Gen::CompactIdVisitor::visitClassDefStart(const ClassDefPtr& p) return false; } -Slice::Gen::HolderVisitor::HolderVisitor(const string& dir) : - JavaVisitor(dir) -{ -} - -bool -Slice::Gen::HolderVisitor::visitClassDefStart(const ClassDefPtr& p) -{ - ClassDeclPtr decl = p->declaration(); - writeHolder(decl); - - if(!p->isLocal()) - { - string name = p->name(); - string absolute = getAbsolute(p, "", "", "PrxHolder"); - - open(absolute, p->file()); - Output& out = output(); - - out << sp << nl << "public final class " << name << "PrxHolder"; - out << sb; - out << sp << nl << "public" << nl << name << "PrxHolder()"; - out << sb; - out << eb; - out << sp << nl << "public" << nl << name << "PrxHolder(" << name << "Prx value)"; - out << sb; - out << nl << "this.value = value;"; - out << eb; - out << sp << nl << "public " << name << "Prx value;"; - out << eb; - close(); - } - - return false; -} - -bool -Slice::Gen::HolderVisitor::visitStructStart(const StructPtr& p) -{ - writeHolder(p); - return false; -} - -void -Slice::Gen::HolderVisitor::visitSequence(const SequencePtr& p) -{ - if(sequenceHasHolder(p)) - { - writeHolder(p); - } -} - -void -Slice::Gen::HolderVisitor::visitDictionary(const DictionaryPtr& p) -{ - writeHolder(p); -} - -void -Slice::Gen::HolderVisitor::visitEnum(const EnumPtr& p) -{ - writeHolder(p); -} - -void -Slice::Gen::HolderVisitor::writeHolder(const TypePtr& p) -{ - ContainedPtr contained = ContainedPtr::dynamicCast(p); - assert(contained); - string name = contained->name(); - string absolute = getAbsolute(contained, "", "", "Holder"); - - - string file; - if(p->definitionContext()) - { - file = p->definitionContext()->filename(); - } - - open(absolute, file); - Output& out = output(); - - string typeS = typeToString(p, TypeModeIn, getPackage(contained)); - out << sp << nl << "public final class " << name << "Holder"; - BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); - ClassDeclPtr cl = ClassDeclPtr::dynamicCast(p); - if(!p->isLocal() && ((builtin && builtin->kind() == Builtin::KindObject) || cl)) - { - out << " extends Ice.ObjectHolderBase<" << typeS << ">"; - } - else { - out << " extends Ice.Holder<" << typeS << ">"; - } - out << sb; - if(!p->isLocal() && ((builtin && builtin->kind() == Builtin::KindObject) || cl)) - { - out << sp << nl << "public" << nl << name << "Holder()"; - out << sb; - out << eb; - out << sp << nl << "public" << nl << name << "Holder(" << typeS << " value)"; - out << sb; - out << nl << "this.value = value;"; - out << eb; - - out << sp << nl << "public void"; - out << nl << "valueReady(Ice.Object v)"; - out << sb; - out << nl << "if(v == null || v instanceof " << typeS << ")"; - out << sb; - out << nl << "value = (" << typeS << ")v;"; - out << eb; - out << nl << "else"; - out << sb; - out << nl << "IceInternal.Ex.throwUOE(type(), v);"; - out << eb; - out << eb; - out << sp << nl << "public String" << nl << "type()"; - out << sb; - if(cl) - { - if(cl->isInterface()) - { - out << nl << "return _" << cl->name() << "Disp.ice_staticId();"; - } - else - { - out << nl << "return " << typeS << ".ice_staticId();"; - } - } - else - { - out << nl << "return \"" << p->typeId() << "\";"; - } - out << eb; - } - else - { - out << sp << nl << "public" << nl << name << "Holder()"; - out << sb; - out << eb; - out << sp << nl << "public" << nl << name << "Holder(" << typeS << " value)"; - out << sb; - out << nl << "super(value);"; - out << eb; - } - out << eb; - close(); -} - Slice::Gen::HelperVisitor::HelperVisitor(const string& dir) : JavaVisitor(dir) { } -bool -Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) -{ - if(p->isLocal()) - { - return false; - } - - // - // Proxy helper - // - string name = p->name(); - string scoped = p->scoped(); - string package = getPackage(p); - string absolute = getAbsolute(p); - - open(getAbsolute(p, "", "", "PrxHelper"), p->file()); - Output& out = output(); - - // - // A proxy helper class serves two purposes: it implements the - // proxy interface, and provides static helper methods for use - // by applications (e.g., checkedCast, etc.) - // - out << sp; - writeDocComment(out, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class"), - "Provides type-specific helper functions."); - out << nl << "public final class " << name << "PrxHelper extends Ice.ObjectPrxHelperBase implements " << name - << "Prx"; - - out << sb; - - string contextParam = "java.util.Map<String, String> __ctx"; - string explicitContextParam = "boolean __explicitCtx"; - - OperationList ops = p->allOperations(); - for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) - { - OperationPtr op = *r; - const ContainerPtr container = op->container(); - const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - - out << sp; - out << nl << "private static final String __" << op->name() << "_name = \"" << op->name() << "\";"; - - // - // Use the optional mapping by default. - // - writeOperation(p, package, op, true); - - // - // If the operation actually sends any optionals, we generated overloaded methods - // that use the required mapping. - // - if(op->sendsOptionals()) - { - writeOperation(p, package, op, false); - } - - // - // End method - // - vector<string> outParams = getInOutParams(op, package, OutParam, true, true); - int iter = 0; - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); - const TypePtr ret = op->returnType(); - const string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, op->returnIsOptional()); - - out << sp; - out << nl << "public " << retS << " end_" << op->name() << spar << outParams << "Ice.AsyncResult __iresult" - << epar; - writeThrowsClause(package, throws); - out << sb; - if(op->returnsData()) - { - out << nl << "IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__iresult, this, __" - << op->name() << "_name);"; - out << nl << "try"; - out << sb; - - out << nl << "if(!__result.__wait())"; - out << sb; - out << nl << "try"; - out << sb; - out << nl << "__result.throwUserException();"; - out << eb; - // - // Arrange exceptions into most-derived to least-derived order. If we don't - // do this, a base exception handler can appear before a derived exception - // handler, causing compiler warnings and resulting in the base exception - // being marshaled instead of the derived exception. - // -#if defined(__SUNPRO_CC) - throws.sort(Slice::derivedToBaseCompare); -#else - throws.sort(Slice::DerivedToBaseCompare()); -#endif - for(ExceptionList::const_iterator eli = throws.begin(); eli != throws.end(); ++eli) - { - out << nl << "catch(" << getAbsolute(*eli, package) << " __ex)"; - out << sb; - out << nl << "throw __ex;"; - out << eb; - } - out << nl << "catch(Ice.UserException __ex)"; - out << sb; - out << nl << "throw new Ice.UnknownUserException(__ex.ice_id(), __ex);"; - out << eb; - out << eb; - - if(ret || !outParams.empty()) - { - out << nl << "Ice.InputStream __is = __result.startReadParams();"; - const ParamDeclList paramList = op->parameters(); - ParamDeclList pl; - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) - { - if((*pli)->isOutParam()) - { - pl.push_back(*pli); - } - } - writeMarshalUnmarshalParams(out, package, pl, op, iter, false, true); - if(op->returnsClasses(false)) - { - out << nl << "__is.readPendingValues();"; - } - out << nl << "__result.endReadParams();"; - } - else - { - out << nl << "__result.readEmptyParams();"; - } - - if(ret) - { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(ret); - if(!op->returnIsOptional() && - ((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(ret))) - { - out << nl << "return __ret.value;"; - } - else - { - out << nl << "return __ret;"; - } - } - - out << eb; - out << nl << "finally"; - out << sb; - out << nl << "if(__result != null)"; - out << sb; - out << nl << "__result.cacheMessageBuffers();"; - out << eb; - out << eb; - } - else - { - out << nl << "__end(__iresult, __" << op->name() << "_name);"; - } - out << eb; - - // - // The async callbacks implementation of __completed method delegate to the static - // __<op-name>_completed method implemented bellow. - // - if(op->returnsData()) - { - const ParamDeclList paramList = op->parameters(); - ParamDeclList outParams; - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) - { - if((*pli)->isOutParam()) - { - outParams.push_back(*pli); - } - } - - out << sp << nl << "static public void __" << op->name() << "_completed(" - << getAsyncCallbackInterface(op, package) << " __cb, Ice.AsyncResult __result)"; - out << sb; - out << nl << getAbsolute(cl, "", "", "Prx") << " __proxy = (" - << getAbsolute(cl, "", "", "Prx") << ")__result.getProxy();"; - - TypePtr ret = op->returnType(); - if(ret) - { - out << nl << typeToString(ret, TypeModeIn, package, op->getMetaData(), true, - op->returnIsOptional()) - << " __ret = " << (op->returnIsOptional() ? "null" : initValue(ret)) << ';'; - } - for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) - { - string ts = typeToString((*pli)->type(), TypeModeOut, package, (*pli)->getMetaData(), true, - (*pli)->optional()); - out << nl << ts << ' ' << fixKwd((*pli)->name()) << " = new " << ts << "();"; - } - out << nl << "try"; - out << sb; - out << nl; - if(op->returnType()) - { - out << "__ret = "; - } - out << "__proxy.end_" << op->name() << spar << getInOutArgs(op, OutParam) << "__result" << epar - << ';'; - - out << eb; - if(!throws.empty()) - { - out << nl << "catch(Ice.UserException __ex)"; - out << sb; - out << nl << "__cb.exception(__ex);"; - out << nl << "return;"; - out << eb; - } - out << nl << "catch(Ice.LocalException __ex)"; - out << sb; - out << nl << "__cb.exception(__ex);"; - out << nl << "return;"; - out << eb; - out << nl << "catch(Ice.SystemException __ex)"; - out << sb; - out << nl << "__cb.exception(__ex);"; - out << nl << "return;"; - out << eb; - - out << nl << "__cb.response" << spar; - if(op->returnType()) - { - out << "__ret"; - } - for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) - { - if((*pli)->optional()) - { - out << fixKwd((*pli)->name()); - } - else - { - out << fixKwd((*pli)->name()) + ".value"; - } - } - out << epar << ';'; - - out << eb; - } - } - - out << sp; - writeDocComment(out, "", - "Contacts the remote server to verify that the object implements this type.\n" - "Raises a local exception if a communication error occurs.\n" - "@param __obj The untyped proxy.\n" - "@return A proxy for this type, or null if the object does not support this type."); - out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj)"; - out << sb; - out << nl << "return checkedCastImpl(__obj, ice_staticId(), " << name << "Prx.class, " - << name << "PrxHelper.class);"; - out << eb; - - out << sp; - writeDocComment(out, "", - "Contacts the remote server to verify that the object implements this type.\n" - "Raises a local exception if a communication error occurs.\n" - "@param __obj The untyped proxy.\n" - "@param __ctx The Context map to send with the invocation.\n" - "@return A proxy for this type, or null if the object does not support this type."); - out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj, " << contextParam << ')'; - out << sb; - out << nl << "return checkedCastImpl(__obj, __ctx, ice_staticId(), " << name - << "Prx.class, " << name << "PrxHelper.class);"; - out << eb; - - out << sp; - writeDocComment(out, "", - "Contacts the remote server to verify that a facet of the object implements this type.\n" - "Raises a local exception if a communication error occurs.\n" - "@param __obj The untyped proxy.\n" - "@param __facet The name of the desired facet.\n" - "@return A proxy for this type, or null if the object does not support this type."); - out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj, String __facet)"; - out << sb; - out << nl << "return checkedCastImpl(__obj, __facet, ice_staticId(), " << name - << "Prx.class, " << name << "PrxHelper.class);"; - out << eb; - - out << sp; - writeDocComment(out, "", - "Contacts the remote server to verify that a facet of the object implements this type.\n" - "Raises a local exception if a communication error occurs.\n" - "@param __obj The untyped proxy.\n" - "@param __facet The name of the desired facet.\n" - "@param __ctx The Context map to send with the invocation.\n" - "@return A proxy for this type, or null if the object does not support this type."); - out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj, String __facet, " - << contextParam << ')'; - out << sb; - out << nl << "return checkedCastImpl(__obj, __facet, __ctx, ice_staticId(), " << name - << "Prx.class, " << name << "PrxHelper.class);"; - out << eb; - - out << sp; - writeDocComment(out, "", - "Downcasts the given proxy to this type without contacting the remote server.\n" - "@param __obj The untyped proxy.\n" - "@return A proxy for this type."); - out << nl << "public static " << name << "Prx uncheckedCast(Ice.ObjectPrx __obj)"; - out << sb; - out << nl << "return uncheckedCastImpl(__obj, " << name << "Prx.class, " << name - << "PrxHelper.class);"; - out << eb; - - out << sp; - writeDocComment(out, "", - "Downcasts the given proxy to this type without contacting the remote server.\n" - "@param __obj The untyped proxy.\n" - "@param __facet The name of the desired facet.\n" - "@return A proxy for this type."); - out << nl << "public static " << name << "Prx uncheckedCast(Ice.ObjectPrx __obj, String __facet)"; - out << sb; - out << nl << "return uncheckedCastImpl(__obj, __facet, " << name << "Prx.class, " << name - << "PrxHelper.class);"; - out << eb; - - ClassList allBases = p->allBases(); - StringList ids; - transform(allBases.begin(), allBases.end(), back_inserter(ids), constMemFun(&Contained::scoped)); - StringList other; - other.push_back(scoped); - other.push_back("::Ice::Object"); - other.sort(); - ids.merge(other); - ids.unique(); - StringList::const_iterator firstIter = ids.begin(); - StringList::const_iterator scopedIter = find(ids.begin(), ids.end(), scoped); - assert(scopedIter != ids.end()); - StringList::difference_type scopedPos = ::IceUtilInternal::distance(firstIter, scopedIter); - - out << sp << nl << "public static final String[] __ids ="; - out << sb; - - for(StringList::const_iterator q = ids.begin(); q != ids.end();) - { - out << nl << '"' << *q << '"'; - if(++q != ids.end()) - { - out << ','; - } - } - - out << eb << ';'; - - out << sp; - writeDocComment(out, "", - "Provides the Slice type ID of this type.\n" - "@return The Slice type ID."); - out << nl << "public static String ice_staticId()"; - out << sb; - out << nl << "return __ids[" << scopedPos << "];"; - out << eb; - - out << sp << nl << "public static void write(Ice.OutputStream __os, " << name << "Prx v)"; - out << sb; - out << nl << "__os.writeProxy(v);"; - out << eb; - - out << sp << nl << "public static " << name << "Prx read(Ice.InputStream __is)"; - out << sb; - out << nl << "Ice.ObjectPrx proxy = __is.readProxy();"; - out << nl << "if(proxy != null)"; - out << sb; - out << nl << name << "PrxHelper result = new " << name << "PrxHelper();"; - out << nl << "result.__copyFrom(proxy);"; - out << nl << "return result;"; - out << eb; - out << nl << "return null;"; - out << eb; - - // - // Avoid serialVersionUID warnings for Proxy Helper classes. - // - out << sp << nl << "public static final long serialVersionUID = 0L;"; - out << eb; - - close(); - - return false; -} - void Slice::Gen::HelperVisitor::visitSequence(const SequencePtr& p) { @@ -5167,7 +3984,7 @@ Slice::Gen::HelperVisitor::visitSequence(const SequencePtr& p) bool suppressUnchecked = false; string instanceType, formalType; - bool customType = getSequenceTypes(p, "", StringList(), instanceType, formalType); + bool customType = getSequenceTypes(p, "", StringList(), instanceType, formalType, false); if(!customType) { @@ -5203,7 +4020,7 @@ Slice::Gen::HelperVisitor::visitSequence(const SequencePtr& p) out << sp << nl << "public final class " << name << "Helper"; out << sb; - out << nl << "public static void" << nl << "write(Ice.OutputStream __os, " << typeS << " __v)"; + out << nl << "public static void write(com.zeroc.Ice.OutputStream __os, " << typeS << " __v)"; out << sb; iter = 0; writeSequenceMarshalUnmarshalCode(out, package, p, "__v", true, iter, false); @@ -5214,7 +4031,7 @@ Slice::Gen::HelperVisitor::visitSequence(const SequencePtr& p) { out << nl << "@SuppressWarnings(\"unchecked\")"; } - out << nl << "public static " << typeS << nl << "read(Ice.InputStream __is)"; + out << nl << "public static " << typeS << " read(com.zeroc.Ice.InputStream __is)"; out << sb; out << nl << typeS << " __v;"; iter = 0; @@ -5255,14 +4072,13 @@ Slice::Gen::HelperVisitor::visitDictionary(const DictionaryPtr& p) out << sp << nl << "public final class " << name << "Helper"; out << sb; - out << nl << "public static void" << nl << "write(Ice.OutputStream __os, " << formalType << " __v)"; + out << nl << "public static void write(com.zeroc.Ice.OutputStream __os, " << formalType << " __v)"; out << sb; iter = 0; writeDictionaryMarshalUnmarshalCode(out, package, p, "__v", true, iter, false); out << eb; - out << sp << nl << "public static " << formalType - << nl << "read(Ice.InputStream __is)"; + out << sp << nl << "public static " << formalType << " read(com.zeroc.Ice.InputStream __is)"; out << sb; out << nl << formalType << " __v;"; iter = 0; @@ -5274,691 +4090,711 @@ Slice::Gen::HelperVisitor::visitDictionary(const DictionaryPtr& p) close(); } -void -Slice::Gen::HelperVisitor::writeOperation(const ClassDefPtr& p, const string& package, const OperationPtr& op, - bool optionalMapping) +Slice::Gen::ProxyVisitor::ProxyVisitor(const string& dir) : + JavaVisitor(dir) { - const string name = p->name(); - Output& out = output(); - - const string contextParam = "java.util.Map<String, String> __ctx"; - const string explicitContextParam = "boolean __explicitCtx"; - - const ContainerPtr container = op->container(); - const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - const string opName = fixKwd(op->name()); - const TypePtr ret = op->returnType(); - const string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, op->returnIsOptional()); - - vector<string> params = getParamsProxy(op, package, false, optionalMapping); - vector<string> args = getArgs(op); +} - ParamDeclList inParams; - ParamDeclList outParams; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) +bool +Slice::Gen::ProxyVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal()) { - if((*pli)->isOutParam()) - { - outParams.push_back(*pli); - } - else - { - inParams.push_back(*pli); - } + return false; } - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); - // - // Write two synchronous versions of the operation - with and without a - // context parameter. + // Don't generate a proxy interface for a class with no operations. // - out << sp << nl << "public " << retS << ' ' << opName << spar << params << epar; - writeThrowsClause(package, throws); - out << sb; - out << nl; - if(ret) + const OperationList ops = p->allOperations(); + if(!p->isInterface() && ops.empty()) { - out << "return "; + return false; } - out << opName << spar << args << "null" << "false" << epar << ';'; - out << eb; - out << sp << nl << "public " << retS << ' ' << opName << spar << params << contextParam << epar; - writeThrowsClause(package, throws); - out << sb; - out << nl; - if(ret) - { - out << "return "; - } - out << opName << spar << args << "__ctx" << "true" << epar << ';'; - out << eb; + string name = p->name(); + ClassList bases = p->bases(); + string package = getPackage(p); + string absolute = getAbsolute(p, "", "", "Prx"); - out << sp; - out << nl << "private " << retS << ' ' << opName << spar << params << contextParam - << explicitContextParam << epar; - writeThrowsClause(package, throws); - out << sb; + open(absolute, p->file()); - // This code replaces the synchronous calls with chained AMI calls. - if(op->returnsData()) + Output& out = output(); + + // + // For proxy purposes, we can ignore a base class if it has no operations. + // + if(!bases.empty() && !bases.front()->isInterface() && bases.front()->allOperations().empty()) { - out << nl << "__checkTwowayOnly(__" << op->name() << "_name);"; + bases.pop_front(); } - if(ret) + // + // Generate a Java interface as the user-visible type + // + out << sp; + writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); + out << nl << "public interface " << name << "Prx extends "; + out.useCurrentPosAsIndent(); + if(bases.empty()) { - out << nl << "return "; + out << "com.zeroc.Ice.ObjectPrx"; } else { - out << nl; - } - - out << "end_" << op->name() << "("; - vector<string> inOutArgs = getInOutArgs(op, OutParam); - if(!inOutArgs.empty()) { - for(vector<string>::const_iterator p = inOutArgs.begin(); p != inOutArgs.end(); ++p) { - out << *p << ", "; - } - } - vector<string> inArgs = getInOutArgs(op, InParam); - out << "begin_" << op->name() << "("; - if(!inArgs.empty()) - { - for(vector<string>::const_iterator p = inArgs.begin(); p != inArgs.end(); ++p) { - out << *p << ", "; + for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) + { + if(q != bases.begin()) + { + out << ',' << nl; + } + out << getAbsolute(*q, package, "", "Prx"); } } - out << "__ctx, __explicitCtx, true, null));"; - out << eb; + out.restoreIndent(); - { - // - // Write the asynchronous begin methods. - // - vector<string> inParams = getInOutParams(op, package, InParam, true, optionalMapping); - vector<string> inArgs = getInOutArgs(op, InParam); - const string callbackParam = "Ice.Callback __cb"; - const ParamDeclList paramList = op->parameters(); - int iter; - - // - // Type-unsafe begin methods - // - out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << epar; - out << sb; - out << nl << "return begin_" << op->name() << spar << inArgs << "null" << "false" << "false" << "null" << epar - << ';'; - out << eb; - - out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << contextParam << epar; - out << sb; - out << nl << "return begin_" << op->name() << spar << inArgs << "__ctx" << "true" << "false" << "null" << epar - << ';'; - out << eb; + out << sb; - out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << callbackParam << epar; - out << sb; - out << nl << "return begin_" << op->name() << spar << inArgs << "null" << "false" << "false" << "__cb" << epar - << ';'; - out << eb; + return true; +} - out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << contextParam - << callbackParam << epar; - out << sb; - out << nl << "return begin_" << op->name() << spar << inArgs << "__ctx" << "true" << "false" << "__cb" << epar - << ';'; - out << eb; +void +Slice::Gen::ProxyVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + Output& out = output(); - // - // Type-safe begin methods - // - string typeSafeCallbackParam; + const string contextParam = "java.util.Map<String, String> __ctx"; - // - // Get the name of the callback using the name of the class in which this - // operation was defined. - // - ContainerPtr container = op->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - string opClassName = getAbsolute(cl, package, "Callback_", '_' + op->name()); - typeSafeCallbackParam = opClassName + " __cb"; + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "static " << p->name() << "Prx checkedCast(com.zeroc.Ice.ObjectPrx __obj)"; + out << sb; + out << nl << "return com.zeroc.Ice.ObjectPrx.__checkedCast(__obj, ice_staticId, " << p->name() + << "Prx.class, _" << p->name() << "PrxI.class);"; + out << eb; - out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << typeSafeCallbackParam - << epar; - out << sb; - out << nl << "return begin_" << op->name() << spar << inArgs << "null" << "false" << "false" << "__cb" << epar - << ';'; - out << eb; + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@param __ctx The Context map to send with the invocation.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "static " << p->name() << "Prx checkedCast(com.zeroc.Ice.ObjectPrx __obj, " << contextParam << ')'; + out << sb; + out << nl << "return com.zeroc.Ice.ObjectPrx.__checkedCast(__obj, __ctx, ice_staticId, " << p->name() + << "Prx.class, _" << p->name() << "PrxI.class);"; + out << eb; - out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << contextParam - << typeSafeCallbackParam << epar; - out << sb; - out << nl << "return begin_" << op->name() << spar << inArgs << "__ctx" << "true" << "false" << "__cb" << epar - << ';'; - out << eb; + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that a facet of the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@param __facet The name of the desired facet.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "static " << p->name() << "Prx checkedCast(com.zeroc.Ice.ObjectPrx __obj, String __facet)"; + out << sb; + out << nl << "return com.zeroc.Ice.ObjectPrx.__checkedCast(__obj, __facet, ice_staticId, " << p->name() + << "Prx.class, _" << p->name() << "PrxI.class);"; + out << eb; - // - // Async methods that accept Java 8 lambda callbacks. - // - out << sp; - out << nl << "public Ice.AsyncResult begin_" << op->name(); - writeParamList(out, getParamsAsyncLambda(op, package, false, false, optionalMapping)); - out << sb; - out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package) << epar << ';'; - out << eb; + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that a facet of the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@param __facet The name of the desired facet.\n" + "@param __ctx The Context map to send with the invocation.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "static " << p->name() << "Prx checkedCast(com.zeroc.Ice.ObjectPrx __obj, String __facet, " + << contextParam << ')'; + out << sb; + out << nl << "return com.zeroc.Ice.ObjectPrx.__checkedCast(__obj, __facet, __ctx, ice_staticId, " << p->name() + << "Prx.class, _" << p->name() << "PrxI.class);"; + out << eb; - out << sp; - out << nl << "public Ice.AsyncResult begin_" << op->name(); - writeParamList(out, getParamsAsyncLambda(op, package, false, true, optionalMapping)); - out << sb; - out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package, false, true) << epar - << ';'; - out << eb; + out << sp; + writeDocComment(out, "", + "Downcasts the given proxy to this type without contacting the remote server.\n" + "@param __obj The untyped proxy.\n" + "@return A proxy for this type."); + out << nl << "static " << p->name() << "Prx uncheckedCast(com.zeroc.Ice.ObjectPrx __obj)"; + out << sb; + out << nl << "return com.zeroc.Ice.ObjectPrx.__uncheckedCast(__obj, " << p->name() << "Prx.class, _" + << p->name() << "PrxI.class);"; + out << eb; - out << sp; - out << nl << "public Ice.AsyncResult begin_" << op->name(); - writeParamList(out, getParamsAsyncLambda(op, package, true, false, optionalMapping)); - out << sb; - out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package, true) << epar << ';'; - out << eb; + out << sp; + writeDocComment(out, "", + "Downcasts the given proxy to this type without contacting the remote server.\n" + "@param __obj The untyped proxy.\n" + "@param __facet The name of the desired facet.\n" + "@return A proxy for this type."); + out << nl << "static " << p->name() << "Prx uncheckedCast(com.zeroc.Ice.ObjectPrx __obj, String __facet)"; + out << sb; + out << nl << "return com.zeroc.Ice.ObjectPrx.__uncheckedCast(__obj, __facet, " << p->name() << "Prx.class, _" + << p->name() << "PrxI.class);"; + out << eb; - out << sp; - out << nl << "public Ice.AsyncResult begin_" << op->name(); - writeParamList(out, getParamsAsyncLambda(op, package, true, true, optionalMapping)); - out << sb; - out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package, true, true) << epar - << ';'; - out << eb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the per-proxy context.\n" + "@param newContext The context for the new proxy.\n" + "@return A proxy with the specified per-proxy context."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_context(java.util.Map<String, String> newContext)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_context(newContext);"; + out << eb; - vector<string> params = inParams; - params.push_back(contextParam); - params.push_back("boolean __explicitCtx"); - params.push_back("boolean __synchronous"); - vector<string> asyncParams = getParamsAsyncLambda(op, package, false, true, optionalMapping, false); - copy(asyncParams.begin(), asyncParams.end(), back_inserter(params)); + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the adapter ID.\n" + "@param newAdapterId The adapter ID for the new proxy.\n" + "@return A proxy with the specified adapter ID."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_adapterId(String newAdapterId)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_adapterId(newAdapterId);"; + out << eb; - out << sp; - out << nl << "private Ice.AsyncResult begin_" << op->name(); - writeParamList(out, params); - out << sb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the endpoints.\n" + "@param newEndpoints The endpoints for the new proxy.\n" + "@return A proxy with the specified endpoints."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_endpoints(com.zeroc.Ice.Endpoint[] newEndpoints)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_endpoints(newEndpoints);"; + out << eb; - ParamDeclList outParams = getOutParams(op); + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the locator cache timeout.\n" + "@param newTimeout The new locator cache timeout (in seconds).\n" + "@return A proxy with the specified locator cache timeout."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_locatorCacheTimeout(int newTimeout)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_locatorCacheTimeout(newTimeout);"; + out << eb; - if(!op->returnsData()) - { - params = getInOutArgs(op, InParam); - params.push_back("__ctx"); - params.push_back("__explicitCtx"); - params.push_back("__synchronous"); - params.push_back("new IceInternal.Functional_OnewayCallback(__responseCb, __exceptionCb, __sentCb)"); - out << nl << "return begin_" << op->name(); - writeParamList(out, params); - out << ';'; - } - else if((ret && !outParams.empty()) || (outParams.size() > 1)) - { - params.clear(); - params.push_back(getLambdaResponseCB(op, package) + " responseCb"); - if(!throws.empty()) - { - params.push_back("IceInternal.Functional_GenericCallback1<Ice.UserException> userExceptionCb"); - } - params.push_back("IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb"); - params.push_back("IceInternal.Functional_BoolCallback sentCb"); + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the invocation timeout.\n" + "@param newTimeout The new invocation timeout (in seconds).\n" + "@return A proxy with the specified invocation timeout."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_invocationTimeout(int newTimeout)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_invocationTimeout(newTimeout);"; + out << eb; - out << sp; - out << nl << "class CB extends " << getAsyncCallbackBaseClass(op, true); - out << sb; - out << nl << "public CB"; - writeParamList(out, params); - out << sb; - out << nl << "super(responseCb != null, "; - if(!throws.empty()) - { - out << "userExceptionCb, "; - } - out << "exceptionCb, sentCb);"; - out << nl << "__responseCb = responseCb;"; - out << eb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for connection caching.\n" + "@param newCache <code>true</code> if the new proxy should cache connections; <code>false</code> otherwise.\n" + "@return A proxy with the specified caching policy."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_connectionCached(boolean newCache)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_connectionCached(newCache);"; + out << eb; - out << sp; - out << nl << "public void response" << spar << getParamsAsyncCB(op, package, false, true) << epar; - out << sb; - out << nl << "if(__responseCb != null)"; - out << sb; - out << nl << "__responseCb.apply" << spar; - if(ret) - { - out << "__ret"; - } - out << getInOutArgs(op, OutParam) << epar << ';'; - out << eb; - out << eb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the endpoint selection policy.\n" + "@param newType The new endpoint selection policy.\n" + "@return A proxy with the specified endpoint selection policy."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_endpointSelection(com.zeroc.Ice.EndpointSelectionType newType)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_endpointSelection(newType);"; + out << eb; - out << sp; - out << nl << "public final void __completed(Ice.AsyncResult __result)"; - out << sb; - out << nl << p->name() << "PrxHelper.__" << op->name() << "_completed(this, __result);"; - out << eb; - out << sp; - out << nl << "private final " << getLambdaResponseCB(op, package) << " __responseCb;"; - out << eb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for how it selects endpoints.\n" + "@param b If <code>b</code> is <code>true</code>, only endpoints that use a secure transport are\n" + "used by the new proxy. If <code>b</code> is false, the returned proxy uses both secure and\n" + "insecure endpoints.\n" + "@return A proxy with the specified selection policy."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_secure(boolean b)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_secure(b);"; + out << eb; - out << nl << "return begin_" << op->name() << spar << getInOutArgs(op, InParam) << "__ctx" - << "__explicitCtx" - << "__synchronous" - << (throws.empty() ? "new CB(__responseCb, __exceptionCb, __sentCb)" : - "new CB(__responseCb, __userExceptionCb, __exceptionCb, __sentCb)") - << epar << ';'; - } - else - { - params = getInOutArgs(op, InParam); - params.push_back("__ctx"); - params.push_back("__explicitCtx"); - params.push_back("__synchronous"); - - const string baseClass = getAsyncCallbackBaseClass(op, true); - out << nl << "return begin_" << op->name(); - writeParamList(out, params, false, false); - out << nl - << (throws.empty() ? "new " + baseClass + "(__responseCb, __exceptionCb, __sentCb)" : - "new " + baseClass + "(__responseCb, __userExceptionCb, __exceptionCb, __sentCb)"); - out.inc(); - out << sb; - out << nl << "public final void __completed(Ice.AsyncResult __result)"; - out << sb; - out << nl << p->name() << "PrxHelper.__" << op->name() << "_completed(this, __result);"; - out << eb; - out << eb; - out << ");"; - out.dec(); - out.restoreIndent(); - } - out << eb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the encoding used to marshal parameters.\n" + "@param e The encoding version to use to marshal request parameters.\n" + "@return A proxy with the specified encoding version."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_encodingVersion(com.zeroc.Ice.EncodingVersion e)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_encodingVersion(e);"; + out << eb; - // - // Implementation of begin method - // - params = inParams; - params.push_back(contextParam); - params.push_back("boolean __explicitCtx"); - params.push_back("boolean __synchronous"); - params.push_back("IceInternal.CallbackBase __cb"); + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for its endpoint selection policy.\n" + "@param b If <code>b</code> is <code>true</code>, the new proxy will use secure endpoints for invocations\n" + "and only use insecure endpoints if an invocation cannot be made via secure endpoints. If <code>b</code> is\n" + "<code>false</code>, the proxy prefers insecure endpoints to secure ones.\n" + "@return A proxy with the specified selection policy."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_preferSecure(boolean b)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_preferSecure(b);"; + out << eb; - out << sp; - out << nl << "private Ice.AsyncResult begin_" << op->name(); - writeParamList(out, params); - out << sb; - if(op->returnsData()) - { - out << nl << "__checkAsyncTwowayOnly(__" << op->name() << "_name);"; - } - out << nl << "IceInternal.OutgoingAsync __result = getOutgoingAsync(__" << op->name() - << "_name, __cb);"; - out << nl << "try"; - out << sb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the router.\n" + "@param router The router for the new proxy.\n" + "@return A proxy with the specified router."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_router(com.zeroc.Ice.RouterPrx router)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_router(router);"; + out << eb; - out << nl << "__result.prepare(__" << op->name() << "_name, " << sliceModeToIceMode(op->sendMode()) - << ", __ctx, __explicitCtx, __synchronous);"; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for the locator.\n" + "@param locator The locator for the new proxy.\n" + "@return A proxy with the specified locator."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_locator(com.zeroc.Ice.LocatorPrx locator)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_locator(locator);"; + out << eb; - iter = 0; - if(!inArgs.empty()) - { - out << nl << "Ice.OutputStream __os = __result.startWriteParams(" - << opFormatTypeToString(op) << ");"; - ParamDeclList pl; - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) - { - if(!(*pli)->isOutParam()) - { - pl.push_back(*pli); - } - } - writeMarshalUnmarshalParams(out, package, pl, 0, iter, true, optionalMapping); - if(op->sendsClasses(false)) - { - out << nl << "__os.writePendingValues();"; - } - out << nl << "__result.endWriteParams();"; - } - else - { - out << nl << "__result.writeEmptyParams();"; - } + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for collocation optimization.\n" + "@param b <code>true</code> if the new proxy enables collocation optimization; <code>false</code> otherwise.\n" + "@return A proxy with the specified collocation optimization."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_collocationOptimized(boolean b)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_collocationOptimized(b);"; + out << eb; - out << nl << "__result.invoke();"; - out << eb; - out << nl << "catch(Ice.Exception __ex)"; - out << sb; - out << nl << "__result.abort(__ex);"; - out << eb; - out << nl << "return __result;"; - out << eb; - } -} + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, but uses twoway invocations.\n" + "@return A proxy that uses twoway invocations."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_twoway()"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_twoway();"; + out << eb; -Slice::Gen::ProxyVisitor::ProxyVisitor(const string& dir) : - JavaVisitor(dir) -{ -} + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, but uses oneway invocations.\n" + "@return A proxy that uses oneway invocations."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_oneway()"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_oneway();"; + out << eb; -bool -Slice::Gen::ProxyVisitor::visitClassDefStart(const ClassDefPtr& p) -{ - if(p->isLocal()) - { - return false; - } + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, but uses batch oneway invocations.\n" + "@return A proxy that uses batch oneway invocations."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_batchOneway()"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_batchOneway();"; + out << eb; - string name = p->name(); - ClassList bases = p->bases(); - string package = getPackage(p); - string absolute = getAbsolute(p, "", "", "Prx"); + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, but uses datagram invocations.\n" + "@return A proxy that uses datagram invocations."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_datagram()"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_datagram();"; + out << eb; - open(absolute, p->file()); + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, but uses batch datagram invocations.\n" + "@return A proxy that uses batch datagram invocations."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_batchDatagram()"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_batchDatagram();"; + out << eb; - Output& out = output(); + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for compression.\n" + "@param co <code>true</code> enables compression for the new proxy; <code>false</code> disables compression.\n" + "@return A proxy with the specified compression setting."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_compress(boolean co)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_compress(co);"; + out << eb; - // - // Generate a Java interface as the user-visible type - // out << sp; - writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); - out << nl << "public interface " << name << "Prx extends "; - if(bases.empty()) - { - out << "Ice.ObjectPrx"; - } - else - { - out.useCurrentPosAsIndent(); - for(ClassList::const_iterator q = bases.begin(); q != bases.end();) - { - out << getAbsolute(*q, package, "", "Prx"); - if(++q != bases.end()) - { - out << ',' << nl; - } - } - out.restoreIndent(); - } + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for its connection timeout setting.\n" + "@param t The connection timeout for the proxy in milliseconds.\n" + "@return A proxy with the specified timeout."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_timeout(int t)"; + out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_timeout(t);"; + out << eb; + out << sp; + writeDocComment(out, "", + "Returns a proxy that is identical to this proxy, except for its connection ID.\n" + "@param connectionId The connection ID for the new proxy. An empty string removes the connection ID.\n" + "@return A proxy with the specified connection ID."); + out << nl << "@Override"; + out << nl << "default " << p->name() << "Prx ice_connectionId(String connectionId)"; out << sb; + out << nl << "return (" << p->name() << "Prx)__ice_connectionId(connectionId);"; + out << eb; - return true; -} + out << sp; + out << nl << "final static String ice_staticId = \"" << p->scoped() << "\";"; + out << sp; + out << nl << "static String ice_staticId()"; + out << sb; + out << nl << "return ice_staticId;"; + out << eb; -void -Slice::Gen::ProxyVisitor::visitClassDefEnd(const ClassDefPtr&) -{ - Output& out = output(); out << eb; close(); + + string absolute = getAbsolute(p, "", "_", "PrxI"); + + open(absolute, p->file()); + + Output& outi = output(); + + outi << sp; + outi << nl << "public class _" << p->name() << "PrxI extends com.zeroc.Ice._ObjectPrxI implements " << p->name() + << "Prx"; + outi << sb; + outi << eb; + close(); } void Slice::Gen::ProxyVisitor::visitOperation(const OperationPtr& p) { - string name = fixKwd(p->name()); - ContainerPtr container = p->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - string package = getPackage(cl); + const string name = fixKwd(p->name()); + const ContainerPtr container = p->container(); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + const string package = getPackage(cl); Output& out = output(); - TypePtr ret = p->returnType(); - string retS = typeToString(ret, TypeModeReturn, package, p->getMetaData(), true, p->returnIsOptional()); - vector<string> params = getParamsProxy(p, package, false, true); + const TypePtr ret = p->returnType(); + const string retS = getResultType(p, package, false, false); + const bool returnsParams = ret || !p->outParameters().empty(); + const vector<string> params = getParamsProxy(p, package, false); + const bool sendsOptionals = p->sendsOptionals(); + vector<string> paramsOpt; + if(sendsOptionals) + { + paramsOpt = getParamsProxy(p, package, true); + } + const vector<string> args = getInArgs(p); + ExceptionList throws = p->throws(); throws.sort(); throws.unique(); - string deprecateReason = getDeprecateReason(p, cl, "operation"); - string contextDoc = "@param __ctx The Context map to send with the invocation."; - string contextParam = "java.util.Map<String, String> __ctx"; - string lambdaResponseDoc = "@param __responseCb The lambda response callback."; - string lambdaUserExDoc = "@param __userExceptionCb The lambda user exception callback."; - string lambdaExDoc = "@param __exceptionCb The lambda exception callback."; - string lambdaSentDoc = "@param __sentCb The lambda sent callback."; + // + // Arrange exceptions into most-derived to least-derived order. If we don't + // do this, a base exception handler can appear before a derived exception + // handler, causing compiler warnings and resulting in the base exception + // being marshaled instead of the derived exception. + // +#if defined(__SUNPRO_CC) + throws.sort(Slice::derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif - const bool optional = p->sendsOptionals(); + const string deprecateReason = getDeprecateReason(p, cl, "operation"); + const string contextDoc = "@param __ctx The Context map to send with the invocation."; + const string contextParam = "java.util.Map<String, String> __ctx"; + const string noExplicitContextArg = "com.zeroc.Ice.ObjectPrx.noExplicitContext"; // - // Write two synchronous versions of the operation - with and without a context parameter. + // Synchronous methods with required parameters. // out << sp; writeDocComment(out, p, deprecateReason); - - out << nl << "public " << retS << ' ' << name << spar << params << epar; + out << nl << "default " << retS << ' ' << name << spar << params << epar; writeThrowsClause(package, throws); - out << ';'; + out << sb; + out << nl; + if(returnsParams) + { + out << "return "; + } + out << name << spar << args << noExplicitContextArg << epar << ';'; + out << eb; out << sp; writeDocComment(out, p, deprecateReason, contextDoc); - - out << nl << "public " << retS << ' ' << name << spar << params << contextParam << epar; + out << nl << "default " << retS << ' ' << name << spar << params << contextParam << epar; writeThrowsClause(package, throws); - out << ';'; - - if(optional) + out << sb; + if(throws.empty()) { - // - // Write overloaded versions of the methods using required params. - // - vector<string> reqParams = getParamsProxy(p, package, false, false); + out << nl; + if(returnsParams) + { + out << "return "; + } + out << "__" << p->name() << "Async" << spar << args << "__ctx" << "true" << epar << ".__wait();"; + } + else + { + out << nl << "try"; + out << sb; + out << nl; + if(returnsParams) + { + out << "return "; + } + out << "__" << p->name() << "Async" << spar << args << "__ctx" << "true" << epar << ".__waitUserEx();"; + out << eb; + for(ExceptionList::const_iterator t = throws.begin(); t != throws.end(); ++t) + { + string exS = getAbsolute(*t, package); + out << nl << "catch(" << exS << " __ex)"; + out << sb; + out << nl << "throw __ex;"; + out << eb; + } + out << nl << "catch(com.zeroc.Ice.UserException __ex)"; + out << sb; + out << nl << "throw new com.zeroc.Ice.UnknownUserException(__ex.ice_id(), __ex);"; + out << eb; + } + out << eb; + // + // Synchronous methods using optional parameters (if any). + // + if(sendsOptionals) + { out << sp; writeDocComment(out, p, deprecateReason); - out << nl << "public " << retS << ' ' << name << spar << reqParams << epar; + out << nl << "default " << retS << ' ' << name << spar << paramsOpt << epar; writeThrowsClause(package, throws); - out << ';'; + out << sb; + out << nl; + if(returnsParams) + { + out << "return "; + } + out << name << spar << args << noExplicitContextArg << epar << ';'; + out << eb; out << sp; writeDocComment(out, p, deprecateReason, contextDoc); - out << nl << "public " << retS << ' ' << name << spar << reqParams << contextParam << epar; + out << nl << "default " << retS << ' ' << name << spar << paramsOpt << contextParam << epar; writeThrowsClause(package, throws); - out << ';'; + out << sb; + if(throws.empty()) + { + out << nl; + if(returnsParams) + { + out << "return "; + } + out << "__" << p->name() << "Async" << spar << args << "__ctx" << "true" << epar << ".__wait();"; + } + else + { + out << nl << "try"; + out << sb; + out << nl; + if(returnsParams) + { + out << "return "; + } + out << "__" << p->name() << "Async" << spar << args << "__ctx" << "true" << epar << ".__waitUserEx();"; + out << eb; + for(ExceptionList::const_iterator t = throws.begin(); t != throws.end(); ++t) + { + string exS = getAbsolute(*t, package); + out << nl << "catch(" << exS << " __ex)"; + out << sb; + out << nl << "throw __ex;"; + out << eb; + } + out << nl << "catch(com.zeroc.Ice.UserException __ex)"; + out << sb; + out << nl << "throw new com.zeroc.Ice.UnknownUserException(__ex.ice_id(), __ex);"; + out << eb; + } + out << eb; } - { - // - // Write the asynchronous begin/end methods. - // - // Start with the type-unsafe begin methods. - // - vector<string> inParams = getInOutParams(p, package, InParam, true, true); - string callbackParam = "Ice.Callback __cb"; - string callbackDoc = "@param __cb The asynchronous callback object."; - - out << sp; - writeDocCommentAMI(out, p, InParam); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << epar << ';'; + // + // Asynchronous methods with required parameters. + // + out << sp; + writeDocCommentAMI(out, p, InParam); - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << epar << ';'; + const string future = getFutureType(p, package); - out << sp; - writeDocCommentAMI(out, p, InParam, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << callbackParam << epar << ';'; + out << nl << "default " << future << ' ' << p->name() << "Async" << spar << params << epar; + out << sb; + out << nl << "return __" << p->name() << "Async" << spar << args << noExplicitContextArg << "false" << epar << ';'; + out << eb; - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << callbackParam - << epar << ';'; + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc); - // - // Type-safe begin methods. - // - string typeSafeCallbackParam; + out << nl << "default " << future << ' ' << p->name() << "Async" << spar << params << contextParam << epar; + out << sb; + out << nl << "return __" << p->name() << "Async" << spar << args << "__ctx" << "false" << epar << ';'; + out << eb; - // - // Get the name of the callback using the name of the class in which this - // operation was defined. - // - ContainerPtr container = p->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - string opClassName = getAbsolute(cl, package, "Callback_", '_' + p->name()); - typeSafeCallbackParam = opClassName + " __cb"; + const string futureImpl = getFutureImplType(p, package); - out << sp; - writeDocCommentAMI(out, p, InParam, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << typeSafeCallbackParam - << epar << ';'; + out << sp; + out << nl << "default " << futureImpl << " __" << p->name() << "Async" << spar << params << contextParam + << "boolean __sync" << epar; + out << sb; + out << nl << futureImpl << " __f = new com.zeroc.IceInternal.OutgoingAsync<>(this, \"" << p->name() << "\", " + << sliceModeToIceMode(p->sendMode()) << ", __sync, " + << (throws.empty() ? "null" : "__" + p->name() + "_ex") << ");"; - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam - << typeSafeCallbackParam << epar << ';'; + out << nl << "__f.invoke("; + out.useCurrentPosAsIndent(); + out << (p->returnsData() ? "true" : "false") << ", __ctx, " << opFormatTypeToString(p) + << ", "; + if(!p->inParameters().empty()) + { + out << "__os -> {"; + out.inc(); + writeMarshalProxyParams(out, package, p, false); + out.dec(); + out << nl << '}'; + } + else + { + out << "null"; + } + out << ", "; + if(returnsParams) + { + out << "__is -> {"; + out.inc(); + writeUnmarshalProxyResults(out, package, p); + out.dec(); + out << nl << "}"; + } + else + { + out << "null"; + } + out.restoreIndent(); + out << ");"; + out << nl << "return __f;"; + out << eb; - // - // Generate the Callback Response interface if the operation has more than one - // return parameter. Operations with just one return parameter use one of the - // builtin async callback interfaces. - // + if(!throws.empty()) + { + out << sp << nl << "static final Class<?>[] __" << p->name() << "_ex ="; + out << sb; + for(ExceptionList::const_iterator t = throws.begin(); t != throws.end(); ++t) { - ParamDeclList outParams = getOutParams(p); - if((ret && !outParams.empty()) || outParams.size() > 1) + if(t != throws.begin()) { - vector<string> params = getParamsAsyncCB(p, package, false, true); - out << sp; - out << nl << "public interface " << getLambdaResponseCB(p, package); - out << sb; - out << nl << "void apply" << spar << params << epar << ';'; - out << eb; + out << ","; } + out << nl << getAbsolute(*t, package) << ".class"; } - - // - // Async methods that accept Java 8 lambda callbacks. - // - { - out << sp; - writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package, false, false, true)); - out << ';'; - - out << sp; - writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc, - lambdaSentDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package, false, true, true)); - out << ';'; - - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, - lambdaExDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package, true, false, true)); - out << ';'; - - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, - lambdaExDoc, lambdaSentDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package, true, true, true)); - out << ';'; - } - - vector<string> outParams = getInOutParams(p, package, OutParam, true, true); - - out << sp; - writeDocCommentAMI(out, p, OutParam); - out << nl << "public " << retS << " end_" << p->name() << spar << outParams << "Ice.AsyncResult __result" - << epar; - writeThrowsClause(package, throws); - out << ';'; + out << eb << ';'; } - if(optional) + if(sendsOptionals) { - // - // Write overloaded versions of the methods using required params. - // - vector<string> inParams = getInOutParams(p, package, InParam, true, false); - string callbackParam = "Ice.Callback __cb"; - string callbackDoc = "@param __cb The asynchronous callback object."; - out << sp; writeDocCommentAMI(out, p, InParam); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << epar << ';'; + + const string future = getFutureType(p, package); + + out << nl << "default " << future << ' ' << p->name() << "Async" << spar << paramsOpt << epar; + out << sb; + out << nl << "return __" << p->name() << "Async" << spar << args << noExplicitContextArg << "false" << epar + << ';'; + out << eb; out << sp; writeDocCommentAMI(out, p, InParam, contextDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << epar << ';'; - out << sp; - writeDocCommentAMI(out, p, InParam, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << callbackParam << epar << ';'; + out << nl << "default " << future << ' ' << p->name() << "Async" << spar << paramsOpt << contextParam << epar; + out << sb; + out << nl << "return __" << p->name() << "Async" << spar << args << "__ctx" << "false" << epar << ';'; + out << eb; out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << callbackParam - << epar << ';'; + out << nl << "default " << futureImpl << " __" << p->name() << "Async" << spar << paramsOpt << contextParam + << "boolean __sync" << epar; + out << sb; + out << nl << futureImpl << " __f = new com.zeroc.IceInternal.OutgoingAsync<>(this, \"" << p->name() << "\", " + << sliceModeToIceMode(p->sendMode()) << ", __sync, " + << (throws.empty() ? "null" : "__" + p->name() + "_ex") << ");"; - // - // Async methods that accept Java 8 lambda callbacks. - // + out << nl << "__f.invoke("; + out.useCurrentPosAsIndent(); + out << (p->returnsData() ? "true" : "false") << ", __ctx, " << opFormatTypeToString(p) << ", "; + if(!p->inParameters().empty()) { - out << sp; - writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package)); - out << ';'; - - out << sp; - writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc, - lambdaSentDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package, false, true)); - out << ';'; - - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, - lambdaExDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package, true)); - out << ';'; - - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, - lambdaExDoc, lambdaSentDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name(); - writeParamList(out, getParamsAsyncLambda(p, package, true, true)); - out << ';'; + out << "__os -> {"; + out.inc(); + writeMarshalProxyParams(out, package, p, true); + out.dec(); + out << nl << '}'; } - - // - // Type-safe begin methods. - // - string typeSafeCallbackParam; - - // - // Get the name of the callback using the name of the class in which this - // operation was defined. - // - ContainerPtr container = p->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - string opClassName = getAbsolute(cl, package, "Callback_", '_' + p->name()); - typeSafeCallbackParam = opClassName + " __cb"; - - out << sp; - writeDocCommentAMI(out, p, InParam, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << typeSafeCallbackParam - << epar << ';'; - - out << sp; - writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); - out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam - << typeSafeCallbackParam << epar << ';'; + else + { + out << "null"; + } + out << ", "; + if(returnsParams) + { + out << "__is -> {"; + out.inc(); + writeUnmarshalProxyResults(out, package, p); + out.dec(); + out << nl << "}"; + } + else + { + out << "null"; + } + out.restoreIndent(); + out << ");"; + out << nl << "return __f;"; + out << eb; } } @@ -5970,14 +4806,14 @@ Slice::Gen::DispatcherVisitor::DispatcherVisitor(const string& dir) : bool Slice::Gen::DispatcherVisitor::visitClassDefStart(const ClassDefPtr& p) { - if(p->isLocal() || !p->isInterface()) + if(p->isLocal() || p->isInterface() || p->allOperations().empty()) { return false; } - string name = p->name(); - ClassList bases = p->bases(); - string absolute = getAbsolute(p, "", "_", "Disp"); + const string name = p->name(); + const string absolute = getAbsolute(p, "", "_", "Disp"); + const string package = getPackage(p); open(absolute, p->file()); @@ -5985,675 +4821,345 @@ Slice::Gen::DispatcherVisitor::visitClassDefStart(const ClassDefPtr& p) out << sp; writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); - out << nl << "public abstract class _" << name << "Disp extends Ice.ObjectImpl implements " << fixKwd(name); - out << sb; + out << nl << "public interface _" << name << "Disp"; - out << sp << nl << "protected void" << nl << "ice_copyStateFrom(Ice.Object __obj)"; - out.inc(); - out << nl << "throws java.lang.CloneNotSupportedException"; - out.dec(); + // + // For dispatch purposes, we can ignore a base class if it has no operations. + // + ClassList bases = p->bases(); + if(!bases.empty() && !bases.front()->isInterface() && bases.front()->allOperations().empty()) + { + bases.pop_front(); + } + + if(bases.empty()) + { + out << " extends com.zeroc.Ice.Object"; + } + else + { + out << " extends "; + out.useCurrentPosAsIndent(); + for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) + { + if(q != bases.begin()) + { + out << ',' << nl; + } + if(!(*q)->isInterface()) + { + out << getAbsolute(*q, package, "_", "Disp"); + } + else + { + out << getAbsolute(*q, package); + } + } + out.restoreIndent(); + } out << sb; - out << nl << "throw new java.lang.CloneNotSupportedException();"; - out << eb; - writeDispatchAndMarshalling(out, p); + writeDispatch(out, p); - // - // Avoid serialVersionUID warnings for dispatch classes. - // - out << sp << nl << "public static final long serialVersionUID = 0L;"; out << eb; close(); return false; } -Slice::Gen::BaseImplVisitor::BaseImplVisitor(const string& dir) : +Slice::Gen::ImplVisitor::ImplVisitor(const string& dir) : JavaVisitor(dir) { } -void -Slice::Gen::BaseImplVisitor::writeDecl(Output& out, const string& package, const string& name, const TypePtr& type, - const StringList& metaData, bool optional) +bool +Slice::Gen::ImplVisitor::visitClassDefStart(const ClassDefPtr& p) { - string typeS = typeToString(type, TypeModeIn, package, metaData, true, optional); - out << nl << typeS << ' ' << name; + if(!p->isAbstract()) + { + return false; + } - if(optional) + string name = p->name(); + ClassList bases = p->bases(); + string package = getPackage(p); + string absolute = getAbsolute(p, "", "", "I"); + + open(absolute, p->file()); + + Output& out = output(); + + out << sp << nl << "public final class " << name << 'I'; + if(p->isInterface()) { - out << " = new " << typeS << "();"; + out << " implements " << fixKwd(name); } else { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); - if(builtin) + if(p->isLocal()) { - switch(builtin->kind()) - { - case Builtin::KindBool: - { - out << " = false"; - break; - } - case Builtin::KindByte: - { - out << " = (byte)0"; - break; - } - case Builtin::KindShort: - { - out << " = (short)0"; - break; - } - case Builtin::KindInt: - case Builtin::KindLong: - { - out << " = 0"; - break; - } - case Builtin::KindFloat: - { - out << " = (float)0.0"; - break; - } - case Builtin::KindDouble: - { - out << " = 0.0"; - break; - } - case Builtin::KindString: - { - out << " = \"\""; - break; - } - case Builtin::KindObject: - case Builtin::KindObjectProxy: - case Builtin::KindLocalObject: - case Builtin::KindValue: - { - out << " = null"; - break; - } - } + out << " extends " << fixKwd(name); } else { - EnumPtr en = EnumPtr::dynamicCast(type); - if(en) - { - EnumeratorList enumerators = en->getEnumerators(); - out << " = " << getAbsolute(en, package) << '.' << fixKwd(enumerators.front()->name()); - } - else - { - out << " = null"; - } + out << " implements _" << name << "Disp"; } + } + out << sb; - out << ';'; + out << nl << "public " << name << "I()"; + out << sb; + out << eb; + + OperationList ops = p->allOperations(); + for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + { + writeOperation(out, package, *r, p->isLocal()); } + + out << eb; + close(); + + return false; } -void -Slice::Gen::BaseImplVisitor::writeReturn(Output& out, const TypePtr& type, bool optional) +string +Slice::Gen::ImplVisitor::getDefaultValue(const string& package, const TypePtr& type, bool optional) { + const BuiltinPtr b = BuiltinPtr::dynamicCast(type); if(optional) { - out << nl << "return null;"; + if(b && b->kind() == Builtin::KindDouble) + { + return "java.util.OptionalDouble.empty()"; + } + else if(b && b->kind() == Builtin::KindInt) + { + return "java.util.OptionalInt.empty()"; + } + else if(b && b->kind() == Builtin::KindLong) + { + return "java.util.OptionalLong.empty()"; + } + else + { + return "java.util.Optional.empty()"; + } } else { - BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); - if(builtin) + if(b) { - switch(builtin->kind()) + switch(b->kind()) { case Builtin::KindBool: { - out << nl << "return false;"; + return "false"; break; } case Builtin::KindByte: { - out << nl << "return (byte)0;"; + return "(byte)0"; break; } case Builtin::KindShort: { - out << nl << "return (short)0;"; + return "(short)0"; break; } case Builtin::KindInt: case Builtin::KindLong: { - out << nl << "return 0;"; + return "0"; break; } case Builtin::KindFloat: { - out << nl << "return (float)0.0;"; + return "(float)0.0"; break; } case Builtin::KindDouble: { - out << nl << "return 0.0;"; + return "0.0"; break; } case Builtin::KindString: + { + return "\"\""; + break; + } case Builtin::KindObject: case Builtin::KindObjectProxy: case Builtin::KindLocalObject: case Builtin::KindValue: { - out << nl << "return null;"; + return "null"; break; } } - return; } - - out << nl << "return null;"; - } -} - -void -Slice::Gen::BaseImplVisitor::writeOperation(Output& out, const string& package, const OperationPtr& op, bool local) -{ - string opName = op->name(); - - const TypePtr ret = op->returnType(); - const bool optionalMapping = useOptionalMapping(op); - const StringList opMetaData = op->getMetaData(); - const string retS = typeToString(ret, TypeModeReturn, package, opMetaData, true, - optionalMapping && op->returnIsOptional()); - vector<string> params = getParams(op, package, false, optionalMapping); - - ContainerPtr container = op->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); - - if(!local && (cl->hasMetaData("amd") || op->hasMetaData("amd"))) - { - vector<string> paramsAMD = getParamsAsync(op, package, true, true); - - out << sp << nl << "public void " << opName << "_async" << spar << paramsAMD << "Ice.Current __current" - << epar; - - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); - - // - // Arrange exceptions into most-derived to least-derived order. If we don't - // do this, a base exception handler can appear before a derived exception - // handler, causing compiler warnings and resulting in the base exception - // being marshaled instead of the derived exception. - // -#if defined(__SUNPRO_CC) - throws.sort(Slice::derivedToBaseCompare); -#else - throws.sort(Slice::DerivedToBaseCompare()); -#endif - writeThrowsClause(package, throws); - - out << sb; - - string result = "__r"; - ParamDeclList paramList = op->parameters(); - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) - { - if((*q)->name() == result) - { - result = "_" + result; - break; - } - } - if(ret) - { - writeDecl(out, package, result, ret, opMetaData, optionalMapping && op->returnIsOptional()); - } - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) - { - if((*q)->isOutParam()) - { - writeDecl(out, package, fixKwd((*q)->name()), (*q)->type(), (*q)->getMetaData(), - optionalMapping && (*q)->optional()); - } - } - - out << nl << "__cb.ice_response("; - if(ret) - { - out << result; - } - bool firstOutParam = true; - for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + else { - if((*q)->isOutParam()) + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) { - if(ret || !firstOutParam) - { - out << ", "; - } - out << fixKwd((*q)->name()); - firstOutParam = false; + EnumeratorList enumerators = en->getEnumerators(); + return getAbsolute(en, package) + '.' + fixKwd(enumerators.front()->name()); } } - out << ");"; - - out << eb; - } - else - { - out << sp << nl << "public " << retS << nl << fixKwd(opName) << spar << params; - if(!local) - { - out << "Ice.Current __current"; - } - out << epar; - - ExceptionList throws = op->throws(); - throws.sort(); - throws.unique(); - - if(op->hasMetaData("UserException")) - { - out.inc(); - out << nl << "throws Ice.UserException"; - out.dec(); - } - else - { - writeThrowsClause(package, throws); - } - - out << sb; - - // - // Return value - // - if(ret) - { - writeReturn(out, ret, optionalMapping && op->returnIsOptional()); - } - - out << eb; } -} -Slice::Gen::ImplVisitor::ImplVisitor(const string& dir) : - BaseImplVisitor(dir) -{ + return "null"; } bool -Slice::Gen::ImplVisitor::visitClassDefStart(const ClassDefPtr& p) +Slice::Gen::ImplVisitor::initResult(Output& out, const string& package, const OperationPtr& op) { - if(!p->isAbstract()) - { - return false; - } - - string name = p->name(); - ClassList bases = p->bases(); - string package = getPackage(p); - string absolute = getAbsolute(p, "", "", "I"); + const string retS = getResultType(op, package, false, true); - open(absolute, p->file()); - - Output& out = output(); - - out << sp << nl << "public final class " << name << 'I'; - if(p->isInterface()) + if(op->hasMarshaledResult()) { - if(p->isLocal()) + out << nl << retS << " __r = new " << retS << spar; + const ParamDeclList outParams = op->outParameters(); + if(op->returnType()) { - out << " implements " << fixKwd(name); + out << getDefaultValue(package, op->returnType(), op->returnIsOptional()); } - else + for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p) { - out << " extends _" << name << "Disp"; + out << getDefaultValue(package, (*p)->type(), (*p)->optional()); } + out << "__current" << epar << ';'; } - else + else if(op->returnsMultipleValues()) { - out << " extends " << fixKwd(name); - } - out << sb; - - out << nl << "public" << nl << name << "I()"; - out << sb; - out << eb; - - OperationList ops = p->allOperations(); - for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) - { - writeOperation(out, package, *r, p->isLocal()); - } - - out << eb; - close(); - - return false; -} - -Slice::Gen::ImplTieVisitor::ImplTieVisitor(const string& dir) : - BaseImplVisitor(dir) -{ -} - -bool -Slice::Gen::ImplTieVisitor::visitClassDefStart(const ClassDefPtr& p) -{ - if(!p->isAbstract()) - { - return false; - } - - string name = p->name(); - ClassList bases = p->bases(); - string package = getPackage(p); - string absolute = getAbsolute(p, "", "", "I"); - - open(absolute, p->file()); - - Output& out = output(); - - // - // Use implementation inheritance in the following situations: - // - // * if a class extends another class - // * if a class implements a single interface - // * if an interface extends only one interface - // - bool inheritImpl = (!p->isInterface() && !bases.empty() && !bases.front()->isInterface()) || (bases.size() == 1); - - out << sp << nl << "public class " << name << 'I'; - if(inheritImpl) - { - out << " extends "; - if(bases.front()->isAbstract()) + out << nl << retS << " __r = new " << retS << "();"; + string retval = "returnValue"; + const ParamDeclList outParams = op->outParameters(); + for(ParamDeclList::const_iterator p = outParams.begin(); p != outParams.end(); ++p) { - out << bases.front()->name() << 'I'; + out << nl << "__r." << fixKwd((*p)->name()) << " = " + << getDefaultValue(package, (*p)->type(), (*p)->optional()) << ';'; + if((*p)->name() == "returnValue") + { + retval = "_returnValue"; + } } - else + if(op->returnType()) { - out << fixKwd(bases.front()->name()); + out << nl << "__r." << retval << " = " + << getDefaultValue(package, op->returnType(), op->returnIsOptional()) << ';'; } } - out << " implements " << '_' << name << "Operations"; - if(p->isLocal()) - { - out << "NC"; - } - out << sb; - - out << nl << "public" << nl << name << "I()"; - out << sb; - out << eb; - - OperationList ops = p->allOperations(); - ops.sort(); - - OperationList baseOps; - if(inheritImpl) - { - baseOps = bases.front()->allOperations(); - baseOps.sort(); - } - - for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + else { - if(inheritImpl && binary_search(baseOps.begin(), baseOps.end(), *r)) + TypePtr type = op->returnType(); + bool optional = op->returnIsOptional(); + if(!type) { - out << sp; - out << nl << "/*"; - out << nl << " * Implemented by " << bases.front()->name() << 'I'; - out << nl << " *"; - writeOperation(out, package, *r, p->isLocal()); - out << sp; - out << nl << "*/"; + const ParamDeclList outParams = op->outParameters(); + if(!outParams.empty()) + { + assert(outParams.size() == 1); + type = outParams.front()->type(); + optional = outParams.front()->optional(); + } + } + if(type) + { + out << nl << retS << " __r = " << getDefaultValue(package, type, optional) << ';'; } else { - writeOperation(out, package, *r, p->isLocal()); + return false; } } - out << eb; - close(); - - return false; -} - -Slice::Gen::AsyncVisitor::AsyncVisitor(const string& dir) : - JavaVisitor(dir) -{ + return true; } void -Slice::Gen::AsyncVisitor::visitOperation(const OperationPtr& p) +Slice::Gen::ImplVisitor::writeOperation(Output& out, const string& package, const OperationPtr& op, bool local) { - ContainerPtr container = p->container(); - ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string opName = op->name(); - if(cl->isLocal()) - { - return; - } + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); - string name = p->name(); - string classPkg = getPackage(cl); - StringList opMetaData = p->getMetaData(); + const ContainerPtr container = op->container(); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + const vector<string> params = getParams(op, package); - // - // Generate new-style callback. - // + if(local) { - TypePtr ret = p->returnType(); - ParamDeclList outParams; - ParamDeclList paramList = p->parameters(); - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + out << sp; + out << nl << "@Override"; + out << nl << "public " << getResultType(op, package, false, false) << ' ' << fixKwd(opName) << spar << params + << epar; + if(op->hasMetaData("UserException")) { - if((*pli)->isOutParam()) - { - outParams.push_back(*pli); - } + out.inc(); + out << nl << "throws com.zeroc.Ice.UserException"; + out.dec(); } - - vector<string> params = getParamsAsyncCB(p, classPkg, false, true); - vector<string> args = getInOutArgs(p, OutParam); - ExceptionList throws = p->throws(); - - // - // If the operation has more than one return parameter we generate a Callback - // interface to use in the method signatures. - // - if(p->returnsData() && ((ret && !outParams.empty()) || outParams.size() > 1)) + else { - open(getAbsolute(cl, "", "_Callback_", "_" + name), p->file()); - - Output& out = output(); - - writeDocCommentOp(out, p); - out << sp << nl << "public interface " << ("_Callback_" + cl->name()) << '_' << name - << " extends " << (throws.empty() ? "Ice.TwowayCallback" : "Ice.TwowayCallbackUE"); - out << sb; - out << nl << "public void response" << spar << params << epar << ';'; - out << eb; - - close(); + writeThrowsClause(package, throws); } - - string classNameAsync = "Callback_" + cl->name(); - string absoluteAsync = getAbsolute(cl, "", "Callback_", "_" + name); - - open(absoluteAsync, p->file()); - - Output& out = output(); - - writeDocCommentOp(out, p); - out << sp << nl << "public abstract class " << classNameAsync << '_' << name; - - if(p->returnsData()) + out << sb; + if(initResult(out, package, op)) { - out.inc(); - out << nl << "extends " << getAsyncCallbackBaseClass(p, false); - out.dec(); - out << sb; - - out << sp << nl << "public final void __completed(Ice.AsyncResult __result)"; - out << sb; - out << nl << cl->name() << "PrxHelper.__" << p->name() << "_completed(this, __result);"; - out << eb; - - out << eb; + out << nl << "return __r;"; } - else + out << eb; + + if(cl->hasMetaData("async-oneway") || op->hasMetaData("async-oneway")) { - out << " extends Ice.OnewayCallback"; + out << sp; + out << nl << "@Override"; + out << nl << getFutureType(op, package) << ' ' << opName << "Async" << spar << params << epar; out << sb; + out << nl << "return null;"; out << eb; } - - close(); } - - if(cl->hasMetaData("amd") || p->hasMetaData("amd")) + else { - string classNameAMD = "AMD_" + cl->name(); - string absoluteAMD = getAbsolute(cl, "", "AMD_", "_" + name); - - string classNameAMDI = "_AMD_" + cl->name(); - string absoluteAMDI = getAbsolute(cl, "", "_AMD_", "_" + name); - - const bool optionalMapping = useOptionalMapping(p); - vector<string> paramsAMD = getParamsAsyncCB(p, classPkg, true, optionalMapping); + const bool amd = cl->hasMetaData("amd") || op->hasMetaData("amd"); + if(amd) { - open(absoluteAMD, p->file()); - - Output& out = output(); - - writeDocCommentOp(out, p); - out << sp << nl << "public interface " << classNameAMD << '_' << name; - out << " extends Ice.AMDCallback"; - out << sb; + const string retS = getResultType(op, package, true, true); out << sp; - writeDocCommentAsync(out, p, OutParam); - out << nl << "void ice_response" << spar << paramsAMD << epar << ';'; - - out << eb; - - close(); - } - - { - open(absoluteAMDI, p->file()); - - Output& out = output(); - - TypePtr ret = p->returnType(); - - ParamDeclList outParams; - ParamDeclList paramList = p->parameters(); - for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) - { - if((*pli)->isOutParam()) - { - outParams.push_back(*pli); - } - } - - ExceptionList throws = p->throws(); - throws.sort(); - throws.unique(); - - // - // Arrange exceptions into most-derived to least-derived order. If we don't - // do this, a base exception handler can appear before a derived exception - // handler, causing compiler warnings and resulting in the base exception - // being marshaled instead of the derived exception. - // -#if defined(__SUNPRO_CC) - throws.sort(Slice::derivedToBaseCompare); -#else - throws.sort(Slice::DerivedToBaseCompare()); -#endif - - int iter; - - out << sp << nl << "final class " << classNameAMDI << '_' << name - << " extends IceInternal.IncomingAsync implements " << classNameAMD << '_' << name; - out << sb; - - out << sp << nl << "public " << classNameAMDI << '_' << name << "(IceInternal.Incoming in)"; - out << sb; - out << nl << "super(in);"; - out << eb; - - out << sp << nl << "public void ice_response" << spar << paramsAMD << epar; - out << sb; - iter = 0; - out << nl << "if(__validateResponse(true))"; + out << nl << "@Override"; + out << nl << "public java.util.concurrent.CompletionStage<" << retS << "> " << opName << "Async" << spar + << params << "com.zeroc.Ice.Current __current" << epar; + writeThrowsClause(package, throws); out << sb; - if(ret || !outParams.empty()) + if(initResult(out, package, op)) { - out << nl << "try"; - out << sb; - out << nl << "Ice.OutputStream __os = this.__startWriteParams(" - << opFormatTypeToString(p) << ");"; - writeMarshalUnmarshalParams(out, classPkg, outParams, p, iter, true, optionalMapping, false); - if(p->returnsClasses(false)) - { - out << nl << "__os.writePendingValues();"; - } - out << nl << "this.__endWriteParams(true);"; - out << eb; - out << nl << "catch(Ice.LocalException __ex)"; - out << sb; - out << nl << "__exception(__ex);"; - out << nl << "return;"; - out << eb; + out << nl << "return java.util.concurrent.CompletableFuture.completedFuture(__r);"; } else { - out << nl << "__writeEmptyParams();"; + out << nl << "return java.util.concurrent.CompletableFuture.completedFuture((Void)null);"; } - out << nl << "__response();"; out << eb; - out << eb; - - if(!throws.empty()) + } + else + { + out << sp; + out << nl << "@Override"; + out << nl << "public " << getResultType(op, package, false, true) << ' ' << fixKwd(opName) << spar << params + << "com.zeroc.Ice.Current __current" << epar; + writeThrowsClause(package, throws); + out << sb; + if(initResult(out, package, op)) { - out << sp << nl << "public void ice_exception(java.lang.Exception ex)"; - out << sb; - out << nl << "try"; - out << sb; - out << nl << "throw ex;"; - out << eb; - for(ExceptionList::const_iterator r = throws.begin(); r != throws.end(); ++r) - { - string exS = getAbsolute(*r, classPkg); - out << nl << "catch(" << exS << " __ex)"; - out << sb; - out << nl << "if(__validateResponse(false))"; - out << sb; - out << nl << "__writeUserException(__ex, " << opFormatTypeToString(p) << ");"; - out << nl << "__response();"; - out << eb; - out << eb; - } - out << nl << "catch(java.lang.Exception __ex)"; - out << sb; - out << nl << "super.ice_exception(__ex);"; - out << eb; - out << eb; + out << nl << "return __r;"; } - out << eb; - - close(); } } } diff --git a/cpp/src/slice2java/Gen.h b/cpp/src/slice2java/Gen.h index bbcd2cb8908..8aa2c46280d 100644 --- a/cpp/src/slice2java/Gen.h +++ b/cpp/src/slice2java/Gen.h @@ -29,38 +29,32 @@ protected: enum ParamDir { InParam, OutParam }; - - ParamDeclList getOutParams(const OperationPtr&); - + std::string getResultType(const OperationPtr&, const std::string&, bool, bool); + void writeResultType(::IceUtilInternal::Output&, const OperationPtr&, const std::string&); + void writeMarshaledResultType(::IceUtilInternal::Output&, const OperationPtr&, const std::string&); + + void allocatePatcher(::IceUtilInternal::Output&, const TypePtr&, const std::string&, const std::string&); + std::string getPatcher(const TypePtr&, const std::string&, const std::string&, bool); + + std::string getFutureType(const OperationPtr&, const std::string&); + std::string getFutureImplType(const OperationPtr&, const std::string&); + // // Compose the parameter lists for an operation. // - std::vector<std::string> getParams(const OperationPtr&, const std::string&, bool, bool); - std::vector<std::string> getParamsProxy(const OperationPtr&, const std::string&, bool, bool); - std::vector<std::string> getInOutParams(const OperationPtr&, const std::string&, ParamDir, bool, bool); - std::vector<std::string> getParamsAsync(const OperationPtr&, const std::string&, bool, bool); - std::vector<std::string> getParamsAsyncCB(const OperationPtr&, const std::string&, bool, bool); - - std::string getAsyncCallbackInterface(const OperationPtr&, const std::string&); - std::string getAsyncCallbackBaseClass(const OperationPtr&, bool); - std::string getLambdaResponseCB(const OperationPtr&, const std::string&); - std::vector<std::string> getParamsAsyncLambda(const OperationPtr&, const std::string&, - bool context = false, bool sentCB = false, - bool optionalMapping = false, - bool inParams = true); - std::vector<std::string> getArgsAsyncLambda(const OperationPtr&, const std::string&, - bool context = false, bool sentCB = false); + std::vector<std::string> getParams(const OperationPtr&, const std::string&); + std::vector<std::string> getParamsProxy(const OperationPtr&, const std::string&, bool); // // Compose the argument lists for an operation. // std::vector<std::string> getArgs(const OperationPtr&); - std::vector<std::string> getInOutArgs(const OperationPtr&, ParamDir); - std::vector<std::string> getArgsAsync(const OperationPtr&); - std::vector<std::string> getArgsAsyncCB(const OperationPtr&); + std::vector<std::string> getInArgs(const OperationPtr&, bool = false); - void writeMarshalUnmarshalParams(::IceUtilInternal::Output&, const std::string&, const ParamDeclList&, - const OperationPtr&, int&, bool, bool, bool = false); + void writeMarshalProxyParams(::IceUtilInternal::Output&, const std::string&, const OperationPtr&, bool); + void writeUnmarshalProxyResults(::IceUtilInternal::Output&, const std::string&, const OperationPtr&); + void writeMarshalServantResults(::IceUtilInternal::Output&, const std::string&, const OperationPtr&, + const std::string&); // // Generate a throws clause containing only non-local exceptions. @@ -77,21 +71,17 @@ protected: // Marshal/unmarshal a data member. // void writeMarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&); - void writeUnmarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&, - bool, int&); - void writeStreamMarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&); - void writeStreamUnmarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&, - bool, int&); + void writeUnmarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&); // - // Generate a patcher class. + // Generate dispatch methods for a class or interface. // - void writePatcher(::IceUtilInternal::Output&, const std::string&, const DataMemberList&, const DataMemberList&); + void writeDispatch(::IceUtilInternal::Output&, const ClassDefPtr&); // - // Generate dispatch and marshalling methods for a class or interface. + // Generate marshaling methods for a class or interface. // - void writeDispatchAndMarshalling(::IceUtilInternal::Output&, const ClassDefPtr&); + void writeMarshaling(::IceUtilInternal::Output&, const ClassDefPtr&); // // Write a constant or default value initializer. @@ -108,17 +98,15 @@ protected: // Write doc comments. // static StringList splitComment(const ContainedPtr&); - static void writeDocComment(::IceUtilInternal::Output&, const ContainedPtr&, - const std::string&, const std::string& = ""); - static void writeDocComment(::IceUtilInternal::Output&, const std::string&, const std::string&); - static void writeDocCommentOp(::IceUtilInternal::Output&, const OperationPtr&); - - static void writeDocCommentAsync(::IceUtilInternal::Output&, const OperationPtr&, - ParamDir, const std::string& = ""); - static void writeDocCommentAMI(::IceUtilInternal::Output&, const OperationPtr&, ParamDir, const std::string& = "", - const std::string& = "", const std::string& = "", const std::string& = "", - const std::string& = ""); - static void writeDocCommentParam(::IceUtilInternal::Output&, const OperationPtr&, ParamDir, bool = true); + void writeDocComment(::IceUtilInternal::Output&, const ContainedPtr&, const std::string&, const std::string& = ""); + void writeDocComment(::IceUtilInternal::Output&, const std::string&, const std::string&); + void writeDocCommentOp(::IceUtilInternal::Output&, const OperationPtr&); + + void writeDocCommentAsync(::IceUtilInternal::Output&, const OperationPtr&, ParamDir, const std::string& = ""); + void writeDocCommentAMI(::IceUtilInternal::Output&, const OperationPtr&, ParamDir, const std::string& = "", + const std::string& = "", const std::string& = "", const std::string& = "", + const std::string& = ""); + void writeDocCommentParam(::IceUtilInternal::Output&, const OperationPtr&, ParamDir, bool = true); }; class Gen : private ::IceUtil::noncopyable @@ -132,9 +120,7 @@ public: ~Gen(); void generate(const UnitPtr&); - void generateTie(const UnitPtr&); void generateImpl(const UnitPtr&); - void generateImplTie(const UnitPtr&); static void writeChecksumClass(const std::string&, const std::string&, const ChecksumMap&); @@ -144,27 +130,6 @@ private: std::vector<std::string> _includePaths; std::string _dir; - class OpsVisitor : public JavaVisitor - { - public: - - OpsVisitor(const std::string&); - - virtual bool visitClassDefStart(const ClassDefPtr&); - - private: - void writeOperations(const ClassDefPtr&, bool); - }; - - class TieVisitor : public JavaVisitor - { - public: - - TieVisitor(const std::string&); - - virtual bool visitClassDefStart(const ClassDefPtr&); - }; - class PackageVisitor : public JavaVisitor { public: @@ -182,6 +147,7 @@ private: virtual bool visitClassDefStart(const ClassDefPtr&); virtual void visitClassDefEnd(const ClassDefPtr&); + virtual void visitOperation(const OperationPtr&); virtual bool visitExceptionStart(const ExceptionPtr&); virtual void visitExceptionEnd(const ExceptionPtr&); virtual bool visitStructStart(const StructPtr&); @@ -207,36 +173,14 @@ private: virtual bool visitClassDefStart(const ClassDefPtr&); }; - class HolderVisitor : public JavaVisitor - { - public: - - HolderVisitor(const std::string&); - - virtual bool visitClassDefStart(const ClassDefPtr&); - virtual bool visitStructStart(const StructPtr&); - virtual void visitSequence(const SequencePtr&); - virtual void visitDictionary(const DictionaryPtr&); - virtual void visitEnum(const EnumPtr&); - - private: - - void writeHolder(const TypePtr&); - }; - class HelperVisitor : public JavaVisitor { public: HelperVisitor(const std::string&); - virtual bool visitClassDefStart(const ClassDefPtr&); virtual void visitSequence(const SequencePtr&); virtual void visitDictionary(const DictionaryPtr&); - - private: - - void writeOperation(const ClassDefPtr&, const std::string&, const OperationPtr&, bool); }; class ProxyVisitor : public JavaVisitor @@ -259,58 +203,31 @@ private: virtual bool visitClassDefStart(const ClassDefPtr&); }; - class BaseImplVisitor : public JavaVisitor + class ImplVisitor : public JavaVisitor { public: - BaseImplVisitor(const std::string&); + ImplVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); protected: // - // Generate code to emit a local variable declaration and initialize it - // if necessary. + // Returns a default value for the type. // - void writeDecl(::IceUtilInternal::Output&, const std::string&, const std::string&, const TypePtr&, - const StringList&, bool); + std::string getDefaultValue(const std::string&, const TypePtr&, bool); // - // Generate code to return a value. + // Generate code to initialize the operation result. // - void writeReturn(::IceUtilInternal::Output&, const TypePtr&, bool); + bool initResult(::IceUtilInternal::Output&, const std::string&, const OperationPtr&); // // Generate an operation. // void writeOperation(::IceUtilInternal::Output&, const std::string&, const OperationPtr&, bool); }; - - class ImplVisitor : public BaseImplVisitor - { - public: - - ImplVisitor(const std::string&); - - virtual bool visitClassDefStart(const ClassDefPtr&); - }; - - class ImplTieVisitor : public BaseImplVisitor - { - public: - - ImplTieVisitor(const std::string&); - - virtual bool visitClassDefStart(const ClassDefPtr&); - }; - - class AsyncVisitor : public JavaVisitor - { - public: - - AsyncVisitor(const std::string&); - - virtual void visitOperation(const OperationPtr&); - }; }; } diff --git a/cpp/src/slice2java/GenCompat.cpp b/cpp/src/slice2java/GenCompat.cpp new file mode 100644 index 00000000000..dc7c4b29a3a --- /dev/null +++ b/cpp/src/slice2java/GenCompat.cpp @@ -0,0 +1,6664 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <GenCompat.h> +#include <Slice/Checksum.h> +#include <Slice/Util.h> +#include <IceUtil/Functional.h> +#include <IceUtil/Iterator.h> +#include <IceUtil/StringUtil.h> +#include <IceUtil/InputUtil.h> +#include <IceUtil/StringConverter.h> +#include <cstring> + +#include <limits> + +using namespace std; +using namespace Slice; +using namespace IceUtil; +using namespace IceUtilInternal; + +namespace +{ + +string +u16CodePoint(unsigned short value) +{ + ostringstream s; + s << "\\u"; + s << hex; + s.width(4); + s.fill('0'); + s << value; + return s.str(); +} + +void +writeU8Buffer(const vector<unsigned char>& u8buffer, ::IceUtilInternal::Output& out) +{ + vector<unsigned short> u16buffer = toUTF16(u8buffer); + + for(vector<unsigned short>::const_iterator c = u16buffer.begin(); c != u16buffer.end(); ++c) + { + out << u16CodePoint(*c); + } +} + +string +sliceModeToIceMode(Operation::Mode opMode) +{ + string mode; + switch(opMode) + { + case Operation::Normal: + { + mode = "Ice.OperationMode.Normal"; + break; + } + case Operation::Nonmutating: + { + mode = "Ice.OperationMode.Nonmutating"; + break; + } + case Operation::Idempotent: + { + mode = "Ice.OperationMode.Idempotent"; + break; + } + default: + { + assert(false); + break; + } + } + return mode; +} + +string +opFormatTypeToString(const OperationPtr& op) +{ + switch(op->format()) + { + case DefaultFormat: + return "Ice.FormatType.DefaultFormat"; + case CompactFormat: + return "Ice.FormatType.CompactFormat"; + case SlicedFormat: + return "Ice.FormatType.SlicedFormat"; + default: + assert(false); + } + + return "???"; +} + +string +getDeprecateReason(const ContainedPtr& p1, const ContainedPtr& p2, const string& type) +{ + string deprecateMetadata, deprecateReason; + if(p1->findMetaData("deprecate", deprecateMetadata) || + (p2 != 0 && p2->findMetaData("deprecate", deprecateMetadata))) + { + deprecateReason = "This " + type + " has been deprecated."; + if(deprecateMetadata.find("deprecate:") == 0 && deprecateMetadata.size() > 10) + { + deprecateReason = deprecateMetadata.substr(10); + } + } + return deprecateReason; +} + +string +initValue(const TypePtr& p) +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + return "false"; + } + case Builtin::KindByte: + { + return "(byte)0"; + } + case Builtin::KindShort: + { + return "(short)0"; + } + case Builtin::KindInt: + case Builtin::KindLong: + { + return "0"; + } + case Builtin::KindFloat: + { + return "(float)0.0"; + } + case Builtin::KindDouble: + { + return "0.0"; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + return "null"; + } + } + } + return "null"; +} + +void +writeParamList(Output& out, vector<string> params, bool end = true, bool newLine = true) +{ + out << "("; + out.useCurrentPosAsIndent(); + for(vector<string>::const_iterator i = params.begin(); i != params.end();) + { + out << (*i); + if(++i != params.end() || !end) + { + out << ", "; + if(newLine) + { + out << nl; + } + } + } + if(end) + { + out << ")"; + out.restoreIndent(); + } +} + +} + +Slice::JavaCompatVisitor::JavaCompatVisitor(const string& dir) : + JavaCompatGenerator(dir) +{ +} + +Slice::JavaCompatVisitor::~JavaCompatVisitor() +{ +} + +ParamDeclList +Slice::JavaCompatVisitor::getOutParams(const OperationPtr& op) +{ + ParamDeclList outParams; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator i = paramList.begin(); i != paramList.end(); ++i) + { + if((*i)->isOutParam()) + { + outParams.push_back(*i); + } + } + return outParams; +} + +vector<string> +Slice::JavaCompatVisitor::getParams(const OperationPtr& op, const string& package, bool local, bool optionalMapping) +{ + vector<string> params; + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + StringList metaData = (*q)->getMetaData(); + bool optional = (*q)->optional(); + if(optional && (local || (*q)->isOutParam())) + { + optional = optionalMapping; + } + string typeString = typeToString((*q)->type(), (*q)->isOutParam() ? TypeModeOut : TypeModeIn, package, + metaData, true, optional); + params.push_back(typeString + ' ' + fixKwd((*q)->name())); + } + + return params; +} + +vector<string> +Slice::JavaCompatVisitor::getParamsProxy(const OperationPtr& op, const string& package, bool final, bool optionalMapping) +{ + vector<string> params; + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + bool optional; + if((*q)->optional()) + { + optional = (*q)->isOutParam() ? true : optionalMapping; + } + else + { + optional = false; + } + + StringList metaData = (*q)->getMetaData(); + string typeString = typeToString((*q)->type(), (*q)->isOutParam() ? TypeModeOut : TypeModeIn, package, + metaData, true, optional); + if(final) + { + typeString = "final " + typeString; + } + params.push_back(typeString + ' ' + fixKwd((*q)->name())); + } + + return params; +} + +vector<string> +Slice::JavaCompatVisitor::getInOutParams(const OperationPtr& op, const string& package, ParamDir paramType, bool /*proxy*/, + bool optionalMapping) +{ + vector<string> params; + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam() == (paramType == OutParam)) + { + bool optional = optionalMapping && (*q)->optional(); + string typeString = typeToString((*q)->type(), paramType == InParam ? TypeModeIn : TypeModeOut, package, + (*q)->getMetaData(), true, optional); + params.push_back(typeString + ' ' + fixKwd((*q)->name())); + } + } + + return params; +} + +vector<string> +Slice::JavaCompatVisitor::getParamsAsync(const OperationPtr& op, const string& package, bool amd, bool optionalMapping) +{ + vector<string> params = getInOutParams(op, package, InParam, !amd, optionalMapping); + + string name = op->name(); + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string classNameAsync = getAbsolute(cl, package, amd ? "AMD_" : "AMI_", '_' + name); + params.insert(params.begin(), classNameAsync + " __cb"); + + return params; +} + +vector<string> +Slice::JavaCompatVisitor::getParamsAsyncCB(const OperationPtr& op, const string& package, bool /*amd*/, bool optionalMapping) +{ + vector<string> params; + + TypePtr ret = op->returnType(); + if(ret) + { + string retS = typeToString(ret, TypeModeIn, package, op->getMetaData(), true, + optionalMapping && op->returnIsOptional()); + params.push_back(retS + " __ret"); + } + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + string typeString = typeToString((*q)->type(), TypeModeIn, package, (*q)->getMetaData(), true, + optionalMapping && (*q)->optional()); + params.push_back(typeString + ' ' + fixKwd((*q)->name())); + } + } + + return params; +} + +namespace +{ + +const char* builtinAsyncCallbackTable[] = +{ + "TwowayCallbackByte", + "TwowayCallbackBool", + "TwowayCallbackShort", + "TwowayCallbackInt", + "TwowayCallbackLong", + "TwowayCallbackFloat", + "TwowayCallbackDouble" +}; + +} + +string +Slice::JavaCompatVisitor::getAsyncCallbackInterface(const OperationPtr& op, const string& package) +{ + TypePtr ret = op->returnType(); + ParamDeclList outParams = getOutParams(op); + bool throws = !op->throws().empty(); + const string suffix = throws ? "UE" : ""; + + if(!ret && outParams.empty()) + { + return throws ? "Ice.TwowayCallbackVoidUE" : "Ice.OnewayCallback"; + } + else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) + { + TypePtr t = ret ? ret : outParams.front()->type(); + bool optional = ret ? op->returnIsOptional() : outParams.front()->optional(); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(t); + if(builtin && !optional) + { + const string prefix = "Ice."; + switch(builtin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + { + return prefix + builtinAsyncCallbackTable[builtin->kind()] + suffix; + } + default: + { + break; + } + } + } + + return "Ice.TwowayCallbackArg1" + suffix + "<" + + typeToString(t, TypeModeIn, package, op->getMetaData(), true, optional) + ">"; + } + else + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + return "_Callback_" + cl->name() + "_" + op->name(); + } +} + +string +Slice::JavaCompatVisitor::getAsyncCallbackBaseClass(const OperationPtr& op, bool functional) +{ + assert(op->returnsData()); + TypePtr ret = op->returnType(); + ParamDeclList outParams = getOutParams(op); + + bool throws = !op->throws().empty(); + const string suffix = throws ? "UE" : ""; + if(!ret && outParams.empty()) + { + assert(throws); + return functional ? + "IceInternal.Functional_TwowayCallbackVoidUE" : + "IceInternal.TwowayCallback implements Ice.TwowayCallbackVoidUE"; + } + else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) + { + TypePtr t = ret ? ret : outParams.front()->type(); + bool optional = ret ? op->returnIsOptional() : outParams.front()->optional(); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(t); + if(builtin && !optional) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + { + ostringstream os; + os << (functional ? "IceInternal.Functional_" : "IceInternal.TwowayCallback implements Ice.") + << builtinAsyncCallbackTable[builtin->kind()] + suffix; + return os.str(); + } + default: + { + break; + } + } + } + + ostringstream os; + if(functional) + { + os << "IceInternal.Functional_TwowayCallbackArg1"; + } + else + { + os << "IceInternal.TwowayCallback implements Ice.TwowayCallbackArg1"; + } + os << suffix << "<" << typeToString(t, TypeModeIn, getPackage(op), op->getMetaData(), true, optional) + ">"; + return os.str(); + } + else + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + ostringstream os; + if(functional) + { + os << "IceInternal.Functional_TwowayCallback" << suffix << " implements "; + } + else + { + os << "IceInternal.TwowayCallback implements "; + } + os << "_Callback_" << cl->name() << "_" << op->name(); + return os.str(); + } +} + +string +Slice::JavaCompatVisitor::getLambdaResponseCB(const OperationPtr& op, const string& package) +{ + TypePtr ret = op->returnType(); + ParamDeclList outParams = getOutParams(op); + if(!ret && outParams.empty()) + { + return "IceInternal.Functional_VoidCallback"; + } + else if((ret && outParams.empty()) || (!ret && outParams.size() == 1)) + { + TypePtr t = ret ? ret : outParams.front()->type(); + bool optional = ret ? op->returnIsOptional() : outParams.front()->optional(); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(t); + if(builtin && !optional) + { + static const char* builtinTable[] = + { + "IceInternal.Functional_ByteCallback", + "IceInternal.Functional_BoolCallback", + "IceInternal.Functional_ShortCallback", + "IceInternal.Functional_IntCallback", + "IceInternal.Functional_LongCallback", + "IceInternal.Functional_FloatCallback", + "IceInternal.Functional_DoubleCallback" + }; + switch(builtin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + { + return builtinTable[builtin->kind()]; + } + default: + { + break; + } + } + } + + return "IceInternal.Functional_GenericCallback1<" + + typeToString(t, TypeModeIn, package, op->getMetaData(), true, optional) + ">"; + } + else + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); + return "FunctionalCallback_" + cl->name() + "_" + op->name() + "_Response"; + } +} + +vector<string> +Slice::JavaCompatVisitor::getParamsAsyncLambda(const OperationPtr& op, const string& package, bool context, bool sentCB, + bool optionalMapping, bool inParams) +{ + vector<string> params; + + if(inParams) + { + params = getInOutParams(op, package, InParam, false, optionalMapping); + } + + if(context) + { + params.push_back("java.util.Map<String, String> __ctx"); + } + + params.push_back(getLambdaResponseCB(op, package) + " __responseCb"); + + if(!op->throws().empty()) + { + params.push_back("IceInternal.Functional_GenericCallback1<Ice.UserException> __userExceptionCb"); + } + + params.push_back("IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb"); + + if(sentCB) + { + params.push_back("IceInternal.Functional_BoolCallback __sentCb"); + } + + return params; +} + +vector<string> +Slice::JavaCompatVisitor::getArgsAsyncLambda(const OperationPtr& op, const string& package, bool context, bool sentCB) +{ + vector<string> args = getInOutArgs(op, InParam); + args.push_back(context ? "__ctx" : "null"); + args.push_back(context ? "true" : "false"); + args.push_back("false"); // __synchronous + args.push_back("__responseCb"); + if(!op->throws().empty()) + { + args.push_back("__userExceptionCb"); + } + args.push_back("__exceptionCb"); + args.push_back(sentCB ? "__sentCb" : "null"); + return args; +} + +vector<string> +Slice::JavaCompatVisitor::getArgs(const OperationPtr& op) +{ + vector<string> args; + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + args.push_back(fixKwd((*q)->name())); + } + + return args; +} + +vector<string> +Slice::JavaCompatVisitor::getInOutArgs(const OperationPtr& op, ParamDir paramType) +{ + vector<string> args; + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam() == (paramType == OutParam)) + { + args.push_back(fixKwd((*q)->name())); + } + } + + return args; +} + +vector<string> +Slice::JavaCompatVisitor::getArgsAsync(const OperationPtr& op) +{ + vector<string> args = getInOutArgs(op, InParam); + args.insert(args.begin(), "__cb"); + return args; +} + +vector<string> +Slice::JavaCompatVisitor::getArgsAsyncCB(const OperationPtr& op) +{ + vector<string> args; + + TypePtr ret = op->returnType(); + if(ret) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(ret); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(ret)) + { + args.push_back("__ret.value"); + } + else + { + args.push_back("__ret"); + } + } + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast((*q)->type()); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast((*q)->type())) + { + args.push_back(fixKwd((*q)->name()) + ".value"); + } + else + { + args.push_back(fixKwd((*q)->name())); + } + } + } + + return args; +} + +void +Slice::JavaCompatVisitor::writeMarshalUnmarshalParams(Output& out, const string& package, const ParamDeclList& params, + const OperationPtr& op, int& iter, bool marshal, bool optionalMapping, + bool dispatch) +{ + ParamDeclList optionals; + for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli) + { + if((*pli)->optional()) + { + optionals.push_back(*pli); + } + else + { + string paramName = fixKwd((*pli)->name()); + bool holder = marshal == dispatch; + string patchParams; + if(!marshal) + { + patchParams = paramName; + } + writeMarshalUnmarshalCode(out, package, (*pli)->type(), OptionalNone, false, 0, paramName, marshal, + iter, holder, (*pli)->getMetaData(), patchParams); + } + } + + TypePtr ret; + bool returnsObject = false; + + if(op && op->returnType()) + { + ret = op->returnType(); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(ret); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(ret); + returnsObject = (builtin && builtin->kind() == Builtin::KindObject) || cl; + const bool optional = optionalMapping && op->returnIsOptional(); + + string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, optional); + bool holder = false; + + if(!marshal) + { + if(optional) + { + out << nl << retS << " __ret = new " << retS << "();"; + } + else if(returnsObject) + { + out << nl << retS << "Holder __ret = new " << retS << "Holder();"; + holder = true; + } + else if(StructPtr::dynamicCast(ret)) + { + out << nl << retS << " __ret = null;"; + } + else + { + out << nl << retS << " __ret;"; + } + } + + if(!op->returnIsOptional()) + { + writeMarshalUnmarshalCode(out, package, ret, OptionalNone, false, 0, "__ret", marshal, iter, holder, + op->getMetaData()); + } + } + + // + // Sort optional parameters by tag. + // + class SortFn + { + public: + static bool compare(const ParamDeclPtr& lhs, const ParamDeclPtr& rhs) + { + return lhs->tag() < rhs->tag(); + } + }; + optionals.sort(SortFn::compare); + + // + // Handle optional parameters. + // + bool checkReturnType = op && op->returnIsOptional(); + + for(ParamDeclList::const_iterator pli = optionals.begin(); pli != optionals.end(); ++pli) + { + if(checkReturnType && op->returnTag() < (*pli)->tag()) + { + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, optionalMapping, op->returnTag(), + "__ret", marshal, iter, false, op->getMetaData()); + checkReturnType = false; + } + + const bool holder = dispatch && (*pli)->isOutParam() && !optionalMapping; + + writeMarshalUnmarshalCode(out, package, (*pli)->type(), + (*pli)->isOutParam() ? OptionalOutParam : OptionalInParam, optionalMapping, + (*pli)->tag(), fixKwd((*pli)->name()), marshal, iter, holder, (*pli)->getMetaData()); + } + + if(checkReturnType) + { + writeMarshalUnmarshalCode(out, package, ret, OptionalReturnParam, optionalMapping, op->returnTag(), "__ret", + marshal, iter, false, op->getMetaData()); + } +} + +void +Slice::JavaCompatVisitor::writeThrowsClause(const string& package, const ExceptionList& throws) +{ + Output& out = output(); + if(throws.size() > 0) + { + out.inc(); + out << nl << "throws "; + out.useCurrentPosAsIndent(); + int count = 0; + for(ExceptionList::const_iterator r = throws.begin(); r != throws.end(); ++r) + { + if(count > 0) + { + out << "," << nl; + } + out << getAbsolute(*r, package); + count++; + } + out.restoreIndent(); + out.dec(); + } +} + +void +Slice::JavaCompatVisitor::writeMarshalDataMember(Output& out, const string& package, const DataMemberPtr& member, int& iter) +{ + if(!member->optional()) + { + writeMarshalUnmarshalCode(out, package, member->type(), OptionalNone, false, 0, fixKwd(member->name()), + true, iter, false, member->getMetaData()); + } + else + { + out << nl << "if(__has_" << member->name() << " && __os.writeOptional(" << member->tag() << ", " + << getOptionalFormat(member->type()) << "))"; + out << sb; + writeMarshalUnmarshalCode(out, package, member->type(), OptionalMember, false, 0, fixKwd(member->name()), true, + iter, false, member->getMetaData()); + out << eb; + } +} + +void +Slice::JavaCompatVisitor::writeUnmarshalDataMember(Output& out, const string& package, const DataMemberPtr& member, + int& iter, bool needPatcher, int& patchIter) +{ + string patchParams; + if(needPatcher) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(member->type()); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(member->type())) + { + ostringstream ostr; + ostr << "new Patcher(" << patchIter++ << ')'; + patchParams = ostr.str(); + } + } + + if(!member->optional()) + { + writeMarshalUnmarshalCode(out, package, member->type(), OptionalNone, false, 0, fixKwd(member->name()), false, + iter, false, member->getMetaData(), patchParams); + } + else + { + out << nl << "if(__has_" << member->name() << " = __is.readOptional(" << member->tag() << ", " + << getOptionalFormat(member->type()) << "))"; + out << sb; + writeMarshalUnmarshalCode(out, package, member->type(), OptionalMember, false, 0, fixKwd(member->name()), false, + iter, false, member->getMetaData(), patchParams); + out << eb; + } +} + +void +Slice::JavaCompatVisitor::writePatcher(Output& out, const string& package, const DataMemberList& classMembers, + const DataMemberList& optionalMembers) +{ + out << sp << nl << "private class Patcher implements Ice.ReadValueCallback"; + out << sb; + if(classMembers.size() > 1) + { + out << sp << nl << "Patcher(int member)"; + out << sb; + out << nl << "__member = member;"; + out << eb; + } + + out << sp << nl << "public void" << nl << "valueReady(Ice.Object v)"; + out << sb; + if(classMembers.size() > 1) + { + out << nl << "switch(__member)"; + out << sb; + } + int memberCount = 0; + for(DataMemberList::const_iterator d = classMembers.begin(); d != classMembers.end(); ++d) + { + if((*d)->optional()) + { + continue; + } + + BuiltinPtr b = BuiltinPtr::dynamicCast((*d)->type()); + if(b) + { + assert(b->kind() == Builtin::KindObject); + } + + if(classMembers.size() > 1) + { + out.dec(); + out << nl << "case " << memberCount << ":"; + out.inc(); + if(b) + { + out << nl << "__typeId = Ice.ObjectImpl.ice_staticId();"; + } + else + { + out << nl << "__typeId = \"" << (*d)->type()->typeId() << "\";"; + } + } + + string memberName = fixKwd((*d)->name()); + if(b) + { + out << nl << memberName << " = v;"; + } + else + { + string memberType = typeToString((*d)->type(), TypeModeMember, package); + out << nl << "if(v == null || v instanceof " << memberType << ")"; + out << sb; + out << nl << memberName << " = (" << memberType << ")v;"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "IceInternal.Ex.throwUOE(type(), v);"; + out << eb; + } + + if(classMembers.size() > 1) + { + out << nl << "break;"; + } + + memberCount++; + } + + for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) + { + BuiltinPtr b = BuiltinPtr::dynamicCast((*d)->type()); + if(b && b->kind() != Builtin::KindObject) + { + continue; + } + + TypePtr paramType = (*d)->type(); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) + { + + if(classMembers.size() > 1) + { + out.dec(); + out << nl << "case " << memberCount << ":"; + out.inc(); + if(b) + { + out << nl << "__typeId = Ice.ObjectImpl.ice_staticId();"; + } + else + { + out << nl << "__typeId = \"" << (*d)->type()->typeId() << "\";"; + } + } + + string capName = (*d)->name(); + capName[0] = toupper(static_cast<unsigned char>(capName[0])); + + if(b) + { + out << nl << "set" << capName << "(v);"; + } + else + { + string memberType = typeToString((*d)->type(), TypeModeMember, package); + out << nl << "if(v == null || v instanceof " << memberType << ")"; + out << sb; + out << nl << "set" << capName << "((" << memberType << ")v);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "IceInternal.Ex.throwUOE(type(), v);"; + out << eb; + } + + if(classMembers.size() > 1) + { + out << nl << "break;"; + } + + memberCount++; + } + } + + if(classMembers.size() > 1) + { + out << eb; + } + out << eb; + + out << sp << nl << "public String" << nl << "type()"; + out << sb; + if(classMembers.size() > 1) + { + out << nl << "return __typeId;"; + } + else + { + out << nl << "return \"" << (*classMembers.begin())->type()->typeId() << "\";"; + } + out << eb; + + if(classMembers.size() > 1) + { + out << sp << nl << "private int __member;"; + out << nl << "private String __typeId;"; + } + + out << eb; +} + +void +Slice::JavaCompatVisitor::writeDispatchAndMarshalling(Output& out, const ClassDefPtr& p) +{ + string name = fixKwd(p->name()); + string package = getPackage(p); + string scoped = p->scoped(); + ClassList bases = p->bases(); + ClassDefPtr base; + if(!bases.empty() && !bases.front()->isInterface()) + { + base = bases.front(); + } + + ClassList allBases = p->allBases(); + StringList ids; + transform(allBases.begin(), allBases.end(), back_inserter(ids), constMemFun(&Contained::scoped)); + StringList other; + other.push_back(scoped); + other.push_back("::Ice::Object"); + other.sort(); + ids.merge(other); + ids.unique(); + StringList::const_iterator firstIter = ids.begin(); + StringList::const_iterator scopedIter = find(ids.begin(), ids.end(), scoped); + assert(scopedIter != ids.end()); + StringList::difference_type scopedPos = ::IceUtilInternal::distance(firstIter, scopedIter); + + out << sp << nl << "public static final String[] __ids ="; + out << sb; + + for(StringList::const_iterator q = ids.begin(); q != ids.end();) + { + out << nl << '"' << *q << '"'; + if(++q != ids.end()) + { + out << ','; + } + } + out << eb << ';'; + + out << sp << nl << "public boolean ice_isA(String s)"; + out << sb; + out << nl << "return java.util.Arrays.binarySearch(__ids, s) >= 0;"; + out << eb; + + out << sp << nl << "public boolean ice_isA(String s, Ice.Current __current)"; + out << sb; + out << nl << "return java.util.Arrays.binarySearch(__ids, s) >= 0;"; + out << eb; + + out << sp << nl << "public String[] ice_ids()"; + out << sb; + out << nl << "return __ids;"; + out << eb; + + out << sp << nl << "public String[] ice_ids(Ice.Current __current)"; + out << sb; + out << nl << "return __ids;"; + out << eb; + + out << sp << nl << "public String ice_id()"; + out << sb; + out << nl << "return __ids[" << scopedPos << "];"; + out << eb; + + out << sp << nl << "public String ice_id(Ice.Current __current)"; + out << sb; + out << nl << "return __ids[" << scopedPos << "];"; + out << eb; + + out << sp << nl << "public static String ice_staticId()"; + out << sb; + out << nl << "return __ids[" << scopedPos << "];"; + out << eb; + + OperationList ops = p->allOperations(); + + // + // Write the "no Current" implementation of each operation. + // + for(OperationList::const_iterator r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = *r; + string opName = op->name(); + + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + assert(cl); + + string deprecateReason = getDeprecateReason(op, cl, "operation"); + + const bool amd = cl->hasMetaData("amd") || op->hasMetaData("amd"); + const bool optionalMapping = useOptionalMapping(op); + + vector<string> params; + vector<string> args; + TypePtr ret; + + if(amd) + { + opName += "_async"; + params = getParamsAsync(op, package, true, true); + args = getArgsAsync(op); + } + else + { + opName = fixKwd(opName); + ret = op->returnType(); + params = getParams(op, package, false, optionalMapping); + args = getArgs(op); + } + + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + + // + // Only generate a "no current" version of the operation if it hasn't been done in a base + // class already, because the "no current" version is final. + // + bool generateOperation = cl == p; // Generate if the operation is defined in this class. + if(!generateOperation) + { + // + // The operation is not defined in this class. + // + if(!bases.empty()) + { + // + // Check if the operation is already implemented by a base class. + // + bool implementedByBase = false; + if(!bases.front()->isInterface()) + { + OperationList baseOps = bases.front()->allOperations(); + OperationList::const_iterator i; + for(i = baseOps.begin(); i != baseOps.end(); ++i) + { + if((*i)->name() == op->name()) + { + implementedByBase = true; + break; + } + } + if(i == baseOps.end()) + { + generateOperation = true; + } + } + if(!generateOperation && !implementedByBase) + { + // + // No base class defines the operation. Check if one of the + // interfaces defines it, in which case this class must provide it. + // + if(bases.front()->isInterface() || bases.size() > 1) + { + generateOperation = true; + } + } + } + } + if(generateOperation) + { + out << sp; + if(amd) + { + writeDocCommentAsync(out, op, InParam); + } + else + { + writeDocComment(out, op, deprecateReason); + } + out << nl << "public final " + << typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, + optionalMapping && op->returnIsOptional()) + << ' ' << opName << spar << params << epar; + if(op->hasMetaData("UserException")) + { + out.inc(); + out << nl << "throws Ice.UserException"; + out.dec(); + } + else + { + writeThrowsClause(package, throws); + } + out << sb << nl; + if(ret) + { + out << "return "; + } + out << opName << spar << args << "null" << epar << ';'; + out << eb; + } + } + + // + // Dispatch operations. We only generate methods for operations + // defined in this ClassDef, because we reuse existing methods + // for inherited operations. + // + ops = p->operations(); + for(OperationList::const_iterator r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = *r; + StringList opMetaData = op->getMetaData(); + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + assert(cl); + string deprecateReason = getDeprecateReason(op, cl, "operation"); + + string opName = op->name(); + out << sp; + if(!deprecateReason.empty()) + { + out << nl << "/** @deprecated **/"; + } + out << nl << "public static Ice.DispatchStatus ___" << opName << '(' << name + << " __obj, IceInternal.Incoming __inS, Ice.Current __current)"; + out << sb; + + const bool amd = cl->hasMetaData("amd") || op->hasMetaData("amd"); + const bool optionalMapping = useOptionalMapping(op); + + if(!amd) + { + TypePtr ret = op->returnType(); + + ParamDeclList inParams; + ParamDeclList outParams; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + outParams.push_back(*pli); + } + else + { + inParams.push_back(*pli); + } + } + + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + + // + // Arrange exceptions into most-derived to least-derived order. If we don't + // do this, a base exception handler can appear before a derived exception + // handler, causing compiler warnings and resulting in the base exception + // being marshaled instead of the derived exception. + // +#if defined(__SUNPRO_CC) + throws.sort(Slice::derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + + int iter; + + out << nl << "__checkMode(" << sliceModeToIceMode(op->mode()) << ", __current.mode);"; + + if(!inParams.empty()) + { + // + // Unmarshal 'in' parameters. + // + out << nl << "Ice.InputStream __is = __inS.startReadParams();"; + for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) + { + TypePtr paramType = (*pli)->type(); + string paramName = fixKwd((*pli)->name()); + string typeS = typeToString(paramType, TypeModeIn, package, (*pli)->getMetaData(), + true, (*pli)->optional()); + if((*pli)->optional()) + { + out << nl << typeS << ' ' << paramName << " = new " << typeS << "();"; + } + else + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) + { + out << nl << typeS << "Holder " << paramName << " = new " << typeS << "Holder();"; + } + else if(StructPtr::dynamicCast(paramType)) + { + out << nl << typeS << ' ' << paramName << " = null;"; + } + else + { + out << nl << typeS << ' ' << paramName << ';'; + } + } + } + iter = 0; + writeMarshalUnmarshalParams(out, package, inParams, 0, iter, false, true, true); + if(op->sendsClasses(false)) + { + out << nl << "__is.readPendingValues();"; + } + out << nl << "__inS.endReadParams();"; + } + else + { + out << nl << "__inS.readEmptyParams();"; + } + + // + // Declare 'out' parameters. + // + for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) + { + string typeS = typeToString((*pli)->type(), TypeModeOut, package, (*pli)->getMetaData(), true, + optionalMapping && (*pli)->optional()); + out << nl << typeS << ' ' << fixKwd((*pli)->name()) << " = new " << typeS << "();"; + } + + // + // Call on the servant. + // + if(!throws.empty()) + { + out << nl << "try"; + out << sb; + } + out << nl; + if(ret) + { + string retS = typeToString(ret, TypeModeReturn, package, opMetaData, true, + optionalMapping && op->returnIsOptional()); + out << retS << " __ret = "; + } + out << "__obj." << fixKwd(opName) << '('; + for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) + { + TypePtr paramType = (*pli)->type(); + out << fixKwd((*pli)->name()); + if(!(*pli)->optional()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) + { + out << ".value"; + } + } + out << ", "; + } + for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) + { + out << fixKwd((*pli)->name()) << ", "; + } + out << "__current);"; + + // + // Marshal 'out' parameters and return value. + // + if(!outParams.empty() || ret) + { + out << nl << "Ice.OutputStream __os = __inS.__startWriteParams(" + << opFormatTypeToString(op) << ");"; + writeMarshalUnmarshalParams(out, package, outParams, op, iter, true, optionalMapping, true); + if(op->returnsClasses(false)) + { + out << nl << "__os.writePendingValues();"; + } + out << nl << "__inS.__endWriteParams(true);"; + } + else + { + out << nl << "__inS.__writeEmptyParams();"; + } + out << nl << "return Ice.DispatchStatus.DispatchOK;"; + + // + // Handle user exceptions. + // + if(!throws.empty()) + { + out << eb; + for(ExceptionList::const_iterator t = throws.begin(); t != throws.end(); ++t) + { + string exS = getAbsolute(*t, package); + out << nl << "catch(" << exS << " ex)"; + out << sb; + out << nl << "__inS.__writeUserException(ex, " << opFormatTypeToString(op) << ");"; + out << nl << "return Ice.DispatchStatus.DispatchUserException;"; + out << eb; + } + } + + out << eb; + } + else + { + ParamDeclList inParams; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if(!(*pli)->isOutParam()) + { + inParams.push_back(*pli); + } + } + + int iter; + + out << nl << "__checkMode(" << sliceModeToIceMode(op->mode()) << ", __current.mode);"; + + if(!inParams.empty()) + { + // + // Unmarshal 'in' parameters. + // + out << nl << "Ice.InputStream __is = __inS.startReadParams();"; + iter = 0; + for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) + { + TypePtr paramType = (*pli)->type(); + string paramName = fixKwd((*pli)->name()); + string typeS = typeToString(paramType, TypeModeIn, package, (*pli)->getMetaData(), + true, (*pli)->optional()); + if((*pli)->optional()) + { + out << nl << typeS << ' ' << paramName << " = new " << typeS << "();"; + } + else + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) + { + out << nl << typeS << "Holder " << paramName << " = new " << typeS << "Holder();"; + } + else if(StructPtr::dynamicCast(paramType)) + { + out << nl << typeS << ' ' << paramName << " = null;"; + } + else + { + out << nl << typeS << ' ' << paramName << ';'; + } + } + } + writeMarshalUnmarshalParams(out, package, inParams, 0, iter, false, true, true); + if(op->sendsClasses(false)) + { + out << nl << "__is.readPendingValues();"; + } + out << nl << "__inS.endReadParams();"; + } + else + { + out << nl << "__inS.readEmptyParams();"; + } + + // + // Call on the servant. + // + string classNameAMD = "AMD_" + p->name(); + out << nl << classNameAMD << '_' << opName << " __cb = new _" << classNameAMD << '_' << opName + << "(__inS);"; + out << nl << "try"; + out << sb; + out << nl << "__obj." << (amd ? opName + "_async" : fixKwd(opName)) << (amd ? "(__cb, " : "("); + for(ParamDeclList::const_iterator pli = inParams.begin(); pli != inParams.end(); ++pli) + { + TypePtr paramType = (*pli)->type(); + out << fixKwd((*pli)->name()); + if(!(*pli)->optional()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(paramType); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(paramType)) + { + out << ".value"; + } + } + out << ", "; + } + out << "__current);"; + out << eb; + out << nl << "catch(java.lang.Exception ex)"; + out << sb; + out << nl << "__cb.ice_exception(ex);"; + out << eb; + out << nl << "return Ice.DispatchStatus.DispatchAsync;"; + + out << eb; + } + } + + OperationList allOps = p->allOperations(); + if(!allOps.empty()) + { + StringList allOpNames; + transform(allOps.begin(), allOps.end(), back_inserter(allOpNames), constMemFun(&Contained::name)); + allOpNames.push_back("ice_id"); + allOpNames.push_back("ice_ids"); + allOpNames.push_back("ice_isA"); + allOpNames.push_back("ice_ping"); + allOpNames.sort(); + allOpNames.unique(); + + out << sp << nl << "private final static String[] __all ="; + out << sb; + for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end();) + { + out << nl << '"' << *q << '"'; + if(++q != allOpNames.end()) + { + out << ','; + } + } + out << eb << ';'; + + out << sp; + for(OperationList::iterator r = allOps.begin(); r != allOps.end(); ++r) + { + // + // Suppress deprecation warnings if this method dispatches to a deprecated operation. + // + OperationPtr op = *r; + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + assert(cl); + string deprecateReason = getDeprecateReason(op, cl, "operation"); + if(!deprecateReason.empty()) + { + out << nl << "@SuppressWarnings(\"deprecation\")"; + break; + } + } + out << nl << "public Ice.DispatchStatus __dispatch(IceInternal.Incoming in, Ice.Current __current)"; + out << sb; + out << nl << "int pos = java.util.Arrays.binarySearch(__all, __current.operation);"; + out << nl << "if(pos < 0)"; + out << sb; + out << nl << "throw new Ice.OperationNotExistException(__current.id, __current.facet, __current.operation);"; + out << eb; + out << sp << nl << "switch(pos)"; + out << sb; + int i = 0; + for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end(); ++q) + { + string opName = *q; + + out << nl << "case " << i++ << ':'; + out << sb; + if(opName == "ice_id") + { + out << nl << "return ___ice_id(this, in, __current);"; + } + else if(opName == "ice_ids") + { + out << nl << "return ___ice_ids(this, in, __current);"; + } + else if(opName == "ice_isA") + { + out << nl << "return ___ice_isA(this, in, __current);"; + } + else if(opName == "ice_ping") + { + out << nl << "return ___ice_ping(this, in, __current);"; + } + else + { + // + // There's probably a better way to do this. + // + for(OperationList::const_iterator t = allOps.begin(); t != allOps.end(); ++t) + { + if((*t)->name() == (*q)) + { + ContainerPtr container = (*t)->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + assert(cl); + if(cl->scoped() == p->scoped()) + { + out << nl << "return ___" << opName << "(this, in, __current);"; + } + else + { + string base; + if(cl->isInterface()) + { + base = getAbsolute(cl, package, "_", "Disp"); + } + else + { + base = getAbsolute(cl, package); + } + out << nl << "return " << base << ".___" << opName << "(this, in, __current);"; + } + break; + } + } + } + out << eb; + } + out << eb; + out << sp << nl << "assert(false);"; + out << nl << "throw new Ice.OperationNotExistException(__current.id, __current.facet, __current.operation);"; + out << eb; + + // + // Check if we need to generate ice_operationAttributes() + // + + map<string, int> attributesMap; + for(OperationList::iterator r = allOps.begin(); r != allOps.end(); ++r) + { + int attributes = (*r)->attributes(); + if(attributes != 0) + { + attributesMap.insert(map<string, int>::value_type((*r)->name(), attributes)); + } + } + + if(!attributesMap.empty()) + { + out << sp << nl << "private final static int[] __operationAttributes ="; + out << sb; + for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end();) + { + int attributes = 0; + string opName = *q; + map<string, int>::iterator it = attributesMap.find(opName); + if(it != attributesMap.end()) + { + attributes = it->second; + } + out << nl << attributes; + if(++q != allOpNames.end()) + { + out << ','; + } + out << " // " << opName; + } + out << eb << ';'; + + out << sp << nl << "public int ice_operationAttributes(String operation)"; + out << sb; + out << nl << "int pos = java.util.Arrays.binarySearch(__all, operation);"; + out << nl << "if(pos < 0)"; + out << sb; + out << nl << "return -1;"; + out << eb; + out << sp << nl << "return __operationAttributes[pos];"; + out << eb; + } + } + + int iter; + DataMemberList members = p->dataMembers(); + DataMemberList optionalMembers = p->orderedOptionalDataMembers(); + bool basePreserved = p->inheritsMetaData("preserve-slice"); + bool preserved = p->hasMetaData("preserve-slice"); + + if(preserved && !basePreserved) + { + out << sp << nl << "public void __write(Ice.OutputStream __os)"; + out << sb; + out << nl << "__os.startValue(__slicedData);"; + out << nl << "__writeImpl(__os);"; + out << nl << "__os.endValue();"; + out << eb; + + out << sp << nl << "public void __read(Ice.InputStream __is)"; + out << sb; + out << nl << "__is.startValue();"; + out << nl << "__readImpl(__is);"; + out << nl << "__slicedData = __is.endValue(true);"; + out << eb; + } + + out << sp << nl << "protected void __writeImpl(Ice.OutputStream __os)"; + out << sb; + out << nl << "__os.startSlice(ice_staticId(), " << p->compactId() << (!base ? ", true" : ", false") << ");"; + iter = 0; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + writeMarshalDataMember(out, package, *d, iter); + } + } + for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) + { + writeMarshalDataMember(out, package, *d, iter); + } + out << nl << "__os.endSlice();"; + if(base) + { + out << nl << "super.__writeImpl(__os);"; + } + out << eb; + + DataMemberList classMembers = p->classDataMembers(); + DataMemberList allClassMembers = p->allClassDataMembers(); + + if(classMembers.size() != 0) + { + writePatcher(out, package, classMembers, optionalMembers); + } + + out << sp << nl << "protected void __readImpl(Ice.InputStream __is)"; + out << sb; + out << nl << "__is.startSlice();"; + + int patchIter = 0; + const bool needCustomPatcher = classMembers.size() > 1; + iter = 0; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + } + } + for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) + { + writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + } + out << nl << "__is.endSlice();"; + if(base) + { + out << nl << "super.__readImpl(__is);"; + } + out << eb; + + if(preserved && !basePreserved) + { + out << sp << nl << "protected Ice.SlicedData __slicedData;"; + } +} + +void +Slice::JavaCompatVisitor::writeConstantValue(Output& out, const TypePtr& type, const SyntaxTreeBasePtr& valueType, + const string& value, const string& package) +{ + ConstPtr constant = ConstPtr::dynamicCast(valueType); + if(constant) + { + out << getAbsolute(constant, package) << ".value"; + } + else + { + BuiltinPtr bp; + EnumPtr ep; + if((bp = BuiltinPtr::dynamicCast(type))) + { + switch(bp->kind()) + { + case Builtin::KindString: + { + // + // Expand strings into the basic source character set. We can't use isalpha() and the like + // here because they are sensitive to the current locale. + // + static const string basicSourceChars = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_{}[]#()<>%:;.?*+-/^&|~!=,\\\"' "; + static const set<char> charSet(basicSourceChars.begin(), basicSourceChars.end()); + out << "\""; + + vector<unsigned char> u8buffer; // Buffer to convert multibyte characters + + for(size_t i = 0; i < value.size();) + { + if(charSet.find(value[i]) == charSet.end()) + { + char c = value[i]; + if(static_cast<unsigned char>(c) < 128) // Single byte character + { + // + // Print as unicode if not in basic source character set + // + switch(c) + { + // + // Java doesn't want '\n' or '\r\n' encoded as universal + // characters, that gives an error "unclosed string literal" + // + case '\r': + { + out << "\\r"; + break; + } + case '\n': + { + out << "\\n"; + break; + } + default: + { + out << u16CodePoint(c); + break; + } + } + } + else + { + u8buffer.push_back(value[i]); + } + } + else + { + // + // Write any pedding characters in the utf8 buffer + // + if(!u8buffer.empty()) + { + writeU8Buffer(u8buffer, out); + u8buffer.clear(); + } + switch(value[i]) + { + case '\\': + { + string s = "\\"; + size_t j = i + 1; + for(; j < value.size(); ++j) + { + if(value[j] != '\\') + { + break; + } + s += "\\"; + } + + // + // An even number of slash \ will escape the backslash and + // the codepoint will be interpreted as its charaters + // + // \\U00000041 - ['\\', 'U', '0', '0', '0', '0', '0', '0', '4', '1'] + // \\\U00000041 - ['\\', 'A'] (41 is the codepoint for 'A') + // + if(s.size() % 2 != 0 && (value[j] == 'U' || value[j] == 'u')) + { + size_t sz = value[j] == 'U' ? 8 : 4; + out << s.substr(0, s.size() - 1); + i = j + 1; + + string codepoint = value.substr(j + 1, sz); + assert(codepoint.size() == sz); + + IceUtil::Int64 v = IceUtilInternal::strToInt64(codepoint.c_str(), 0, 16); + + + // + // Java doesn't like this special characters encoded as universal characters + // + if(v == 0x5c) + { + out << "\\\\"; + } + else if(v == 0xa) + { + out << "\\n"; + } + else if(v == 0xd) + { + out << "\\r"; + } + else if(v == 0x22) + { + out << "\\\""; + } + // + // Unicode character in the range U+10000 to U+10FFFF is not permitted in a character literal + // and is represented using a Unicode surrogate pair. + // + else if(v > 0xFFFF) + { + unsigned int high = ((static_cast<unsigned int>(v) - 0x10000) / 0x400) + 0xD800; + unsigned int low = ((static_cast<unsigned int>(v) - 0x10000) % 0x400) + 0xDC00; + out << u16CodePoint(high); + out << u16CodePoint(low); + } + else + { + out << u16CodePoint(static_cast<unsigned int>(v)); + } + + i = j + 1 + sz; + } + else + { + out << s; + i = j; + } + continue; + } + case '"': + { + out << "\\"; + break; + } + } + out << value[i]; // Print normally if in basic source character set + } + i++; + } + + // + // Write any pedding characters in the utf8 buffer + // + if(!u8buffer.empty()) + { + writeU8Buffer(u8buffer, out); + u8buffer.clear(); + } + + out << "\""; + break; + } + case Builtin::KindByte: + { + int i = atoi(value.c_str()); + if(i > 127) + { + i -= 256; + } + out << i; // Slice byte runs from 0-255, Java byte runs from -128 - 127. + break; + } + case Builtin::KindLong: + { + out << value << "L"; // Need to append "L" modifier for long constants. + break; + } + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindDouble: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + out << value; + break; + } + case Builtin::KindFloat: + { + out << value << "F"; + break; + } + } + + } + else if((ep = EnumPtr::dynamicCast(type))) + { + string val = value; + string::size_type pos = val.rfind(':'); + if(pos != string::npos) + { + val.erase(0, pos + 1); + } + out << getAbsolute(ep, package) << '.' << fixKwd(val); + } + else + { + out << value; + } + } +} + +void +Slice::JavaCompatVisitor::writeDataMemberInitializers(Output& out, const DataMemberList& members, const string& package) +{ + for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p) + { + TypePtr t = (*p)->type(); + if((*p)->defaultValueType()) + { + if((*p)->optional()) + { + string capName = (*p)->name(); + capName[0] = toupper(static_cast<unsigned char>(capName[0])); + out << nl << "set" << capName << '('; + writeConstantValue(out, t, (*p)->defaultValueType(), (*p)->defaultValue(), package); + out << ");"; + } + else + { + out << nl << fixKwd((*p)->name()) << " = "; + writeConstantValue(out, t, (*p)->defaultValueType(), (*p)->defaultValue(), package); + out << ';'; + } + } + else + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(t); + if(builtin && builtin->kind() == Builtin::KindString) + { + out << nl << fixKwd((*p)->name()) << " = \"\";"; + } + + EnumPtr en = EnumPtr::dynamicCast(t); + if(en) + { + string firstEnum = fixKwd(en->getEnumerators().front()->name()); + out << nl << fixKwd((*p)->name()) << " = " << getAbsolute(en, package) << '.' << firstEnum << ';'; + } + + StructPtr st = StructPtr::dynamicCast(t); + if(st) + { + string memberType = typeToString(st, TypeModeMember, package, (*p)->getMetaData()); + out << nl << fixKwd((*p)->name()) << " = new " << memberType << "();"; + } + } + } +} + +StringList +Slice::JavaCompatVisitor::splitComment(const ContainedPtr& p) +{ + StringList result; + + string comment = p->comment(); + string::size_type pos = 0; + string::size_type nextPos; + while((nextPos = comment.find_first_of('\n', pos)) != string::npos) + { + result.push_back(string(comment, pos, nextPos - pos)); + pos = nextPos + 1; + } + string lastLine = string(comment, pos); + if(lastLine.find_first_not_of(" \t\n\r") != string::npos) + { + result.push_back(lastLine); + } + + return result; +} + +void +Slice::JavaCompatVisitor::writeDocComment(Output& out, const ContainedPtr& p, const string& deprecateReason, + const string& extraParam) +{ + StringList lines = splitComment(p); + if(lines.empty()) + { + if(!deprecateReason.empty()) + { + out << nl << "/**"; + out << nl << " * @deprecated " << deprecateReason; + out << nl << " **/"; + } + return; + } + + out << nl << "/**"; + + bool doneExtraParam = false; + for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i) + { + // + // @param must precede @return, so emit any extra parameter + // when @return is seen. + // + if(i->find("@return") != string::npos && !extraParam.empty()) + { + out << nl << " * " << extraParam; + doneExtraParam = true; + } + out << nl << " *"; + if(!(*i).empty()) + { + out << " " << *i; + } + } + + if(!doneExtraParam && !extraParam.empty()) + { + // + // Above code doesn't emit the comment for the extra parameter + // if the operation returns a void or doesn't have an @return. + // + out << nl << " * " << extraParam; + } + + if(!deprecateReason.empty()) + { + out << nl << " * @deprecated " << deprecateReason; + } + + out << nl << " **/"; +} + +void +Slice::JavaCompatVisitor::writeDocComment(Output& out, const string& deprecateReason, const string& summary) +{ + vector<string> lines; + IceUtilInternal::splitString(summary, "\n", lines); + + out << nl << "/**"; + for(vector<string>::const_iterator i = lines.begin(); i != lines.end(); ++i) + { + out << nl << " *"; + if(!(*i).empty()) + { + out << " " << *i; + } + } + + if(!deprecateReason.empty()) + { + out << nl << " * @deprecated " << deprecateReason; + } + + out << nl << " **/"; +} + +void +Slice::JavaCompatVisitor::writeDocCommentOp(Output& out, const OperationPtr& p) +{ + ContainerPtr container = p->container(); + ContainedPtr contained = ContainedPtr::dynamicCast(container); + string deprecateReason = getDeprecateReason(p, contained, "operation"); + + StringList lines = splitComment(p); + + if(lines.empty() && deprecateReason.empty()) + { + return; + } + + + out << sp << nl << "/**"; + + // + // Output the leading comment block up until the first @tag. + // + bool done = false; + for(StringList::const_iterator i = lines.begin(); i != lines.end() && !done; ++i) + { + if((*i)[0] == '@') + { + done = true; + } + else + { + out << nl << " * " << *i; + } + } + + if(!deprecateReason.empty()) + { + out << nl << " * @deprecated " << deprecateReason; + } + + out << nl << " **/"; +} + +void +Slice::JavaCompatVisitor::writeDocCommentAsync(Output& out, const OperationPtr& p, ParamDir paramType, + const string& extraParam) +{ + ContainerPtr container = p->container(); + ClassDefPtr contained = ClassDefPtr::dynamicCast(container); + string deprecateReason = getDeprecateReason(p, contained, "operation"); + + StringList lines = splitComment(p); + if(lines.empty() && deprecateReason.empty()) + { + return; + } + + out << nl << "/**"; + + if(paramType == OutParam) + { + out << nl << " * ice_response indicates that"; + out << nl << " * the operation completed successfully."; + + // + // Find the comment for the return value (if any) and rewrite that as an @param comment. + // + const string returnTag = "@return"; + bool doneReturn = false; + bool foundReturn = false; + for(StringList::const_iterator i = lines.begin(); i != lines.end() && !doneReturn; ++i) + { + if(!foundReturn) + { + if(i->find(returnTag) != string::npos) + { + foundReturn = true; + out << nl << " * @param __ret (return value)" << i->substr(returnTag.length()); + } + } + else + { + if((*i)[0] == '@') + { + doneReturn = true; + } + else + { + out << nl << " * " << *i; + } + } + } + } + else + { + // + // Output the leading comment block up until the first @tag. + // + bool done = false; + for(StringList::const_iterator i = lines.begin(); i != lines.end() && !done; ++i) + { + if((*i)[0] == '@') + { + done = true; + } + else + { + out << nl << " * " << *i; + } + } + } + + // + // Write the comments for the parameters. + // + writeDocCommentParam(out, p, paramType); + + if(!extraParam.empty()) + { + out << nl << " * " << extraParam; + } + + if(paramType == InParam) + { + if(!deprecateReason.empty()) + { + out << nl << " * @deprecated " << deprecateReason; + } + } + + out << nl << " **/"; +} + +void +Slice::JavaCompatVisitor::writeDocCommentAMI(Output& out, const OperationPtr& p, ParamDir paramType, + const string& extraParam1, const string& extraParam2, const string& extraParam3, + const string& extraParam4, const string& extraParam5) +{ + ContainerPtr container = p->container(); + ClassDefPtr contained = ClassDefPtr::dynamicCast(container); + string deprecateReason = getDeprecateReason(p, contained, "operation"); + + StringList lines = splitComment(p); + if(lines.empty() && deprecateReason.empty()) + { + return; + } + + out << nl << "/**"; + + // + // Output the leading comment block up until the first @tag. + // + bool done = false; + for(StringList::const_iterator i = lines.begin(); i != lines.end() && !done; ++i) + { + if((*i)[0] == '@') + { + done = true; + } + else + { + out << nl << " * " << *i; + } + } + + // + // Write the comments for the parameters. + // + writeDocCommentParam(out, p, paramType, false); + + if(!extraParam1.empty()) + { + out << nl << " * " << extraParam1; + } + + if(!extraParam2.empty()) + { + out << nl << " * " << extraParam2; + } + + if(!extraParam3.empty()) + { + out << nl << " * " << extraParam3; + } + + if(!extraParam4.empty()) + { + out << nl << " * " << extraParam4; + } + + if(!extraParam5.empty()) + { + out << nl << " * " << extraParam5; + } + + if(paramType == InParam) + { + out << nl << " * @return The asynchronous result object."; + if(!deprecateReason.empty()) + { + out << nl << " * @deprecated " << deprecateReason; + } + } + else + { + out << nl << " * @param __result The asynchronous result object."; + // + // Print @return, @throws, and @see tags. + // + const string returnTag = "@return"; + const string throwsTag = "@throws"; + const string seeTag = "@see"; + bool found = false; + for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i) + { + if(!found) + { + if(i->find(returnTag) != string::npos || i->find(throwsTag) != string::npos || + i->find(seeTag) != string::npos) + { + found = true; + } + } + + if(found) + { + out << nl << " * " << *i; + } + } + } + + out << nl << " **/"; +} + +void +Slice::JavaCompatVisitor::writeDocCommentParam(Output& out, const OperationPtr& p, ParamDir paramType, bool cb) +{ + // + // Collect the names of the in- or -out parameters to be documented. + // + ParamDeclList tmp = p->parameters(); + vector<string> params; + for(ParamDeclList::const_iterator q = tmp.begin(); q != tmp.end(); ++q) + { + if((*q)->isOutParam() && paramType == OutParam) + { + params.push_back((*q)->name()); + } + else if(!(*q)->isOutParam() && paramType == InParam) + { + params.push_back((*q)->name()); + } + } + + // + // Print a comment for the callback parameter. + // + if(cb && paramType == InParam) + { + out << nl << " * @param __cb The callback object for the operation."; + } + + // + // Print the comments for all the parameters that appear in the parameter list. + // + const string paramTag = "@param"; + StringList lines = splitComment(p); + StringList::const_iterator i = lines.begin(); + while(i != lines.end()) + { + string line = *i++; + if(line.find(paramTag) != string::npos) + { + string::size_type paramNamePos = line.find_first_not_of(" \t\n\r", paramTag.length()); + if(paramNamePos != string::npos) + { + string::size_type paramNameEndPos = line.find_first_of(" \t", paramNamePos); + string paramName = line.substr(paramNamePos, paramNameEndPos - paramNamePos); + if(std::find(params.begin(), params.end(), paramName) != params.end()) + { + out << nl << " * " << line; + StringList::const_iterator j; + if (i == lines.end()) + { + break; + } + j = i++; + while(j != lines.end()) + { + if((*j)[0] != '@') + { + i = j; + out << nl << " * " << *j++; + } + else + { + break; + } + } + } + } + } + } +} + +Slice::GenCompat::GenCompat(const string& /*name*/, const string& base, const vector<string>& includePaths, const string& dir) : + _base(base), + _includePaths(includePaths), + _dir(dir) +{ +} + +Slice::GenCompat::~GenCompat() +{ +} + +void +Slice::GenCompat::generate(const UnitPtr& p) +{ + JavaGenerator::validateMetaData(p); + + OpsVisitor opsVisitor(_dir); + p->visit(&opsVisitor, false); + + PackageVisitor packageVisitor(_dir); + p->visit(&packageVisitor, false); + + TypesVisitor typesVisitor(_dir); + p->visit(&typesVisitor, false); + + CompactIdVisitor compactIdVisitor(_dir); + p->visit(&compactIdVisitor, false); + + HolderVisitor holderVisitor(_dir); + p->visit(&holderVisitor, false); + + HelperVisitor helperVisitor(_dir); + p->visit(&helperVisitor, false); + + ProxyVisitor proxyVisitor(_dir); + p->visit(&proxyVisitor, false); + + DispatcherVisitor dispatcherVisitor(_dir); + p->visit(&dispatcherVisitor, false); + + AsyncVisitor asyncVisitor(_dir); + p->visit(&asyncVisitor, false); +} + +void +Slice::GenCompat::generateTie(const UnitPtr& p) +{ + TieVisitor tieVisitor(_dir); + p->visit(&tieVisitor, false); +} + +void +Slice::GenCompat::generateImpl(const UnitPtr& p) +{ + ImplVisitor implVisitor(_dir); + p->visit(&implVisitor, false); +} + +void +Slice::GenCompat::generateImplTie(const UnitPtr& p) +{ + ImplTieVisitor implTieVisitor(_dir); + p->visit(&implTieVisitor, false); +} + +void +Slice::GenCompat::writeChecksumClass(const string& checksumClass, const string& dir, const ChecksumMap& m) +{ + // + // Attempt to open the source file for the checksum class. + // + JavaOutput out; + out.openClass(checksumClass, dir); + + // + // Get the class name. + // + string className; + string::size_type pos = checksumClass.rfind('.'); + if(pos == string::npos) + { + className = checksumClass; + } + else + { + className = checksumClass.substr(pos + 1); + } + + // + // Emit the class. + // + out << sp << nl << "public class " << className; + out << sb; + + // + // Use a static initializer to populate the checksum map. + // + out << sp << nl << "public static final java.util.Map<String, String> checksums;"; + out << sp << nl << "static"; + out << sb; + out << nl << "java.util.Map<String, String> map = new java.util.HashMap<String, String>();"; + for(ChecksumMap::const_iterator p = m.begin(); p != m.end(); ++p) + { + out << nl << "map.put(\"" << p->first << "\", \""; + ostringstream str; + str.flags(ios_base::hex); + str.fill('0'); + for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q) + { + str << static_cast<int>(*q); + } + out << str.str() << "\");"; + } + out << nl << "checksums = java.util.Collections.unmodifiableMap(map);"; + + out << eb; + out << eb; + out << nl; +} + +Slice::GenCompat::OpsVisitor::OpsVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::OpsVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + // + // Don't generate an Operations interface for non-abstract classes + // + if(!p->isAbstract()) + { + return false; + } + + if(!p->isLocal()) + { + writeOperations(p, false); + } + writeOperations(p, true); + + return false; +} + +void +Slice::GenCompat::OpsVisitor::writeOperations(const ClassDefPtr& p, bool noCurrent) +{ + string name = p->name(); + ClassList bases = p->bases(); + string package = getPackage(p); + string opIntfName = "Operations"; + if(noCurrent || p->isLocal()) + { + opIntfName += "NC"; + } + string absolute = getAbsolute(p, "", "_", opIntfName); + + open(absolute, p->file()); + + Output& out = output(); + + // + // Generate the operations interface + // + out << sp; + writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); + out << nl << "public interface " << '_' << name << opIntfName; + if((bases.size() == 1 && bases.front()->isAbstract()) || bases.size() > 1) + { + out << " extends "; + out.useCurrentPosAsIndent(); + bool first = true; + for(ClassList::const_iterator q = bases.begin(); q != bases.end();) + { + if((*q)->isAbstract()) + { + if(!first) + { + out << ',' << nl; + } + else + { + first = false; + } + out << getAbsolute(*q, package, "_", opIntfName); + } + ++q; + } + out.restoreIndent(); + } + out << sb; + + OperationList ops = p->operations(); + for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = *r; + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string opname = op->name(); + + TypePtr ret; + vector<string> params; + + const bool amd = !p->isLocal() && (cl->hasMetaData("amd") || op->hasMetaData("amd")); + const bool optionalMapping = useOptionalMapping(op); + + if(amd) + { + params = getParamsAsync(op, package, true, true); + } + else + { + params = getParams(op, package, false, optionalMapping); + ret = op->returnType(); + } + + string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, + optionalMapping && op->returnIsOptional()); + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + out << sp; + + string deprecateReason = getDeprecateReason(*r, p, "operation"); + string extraCurrent; + if(!noCurrent && !p->isLocal()) + { + extraCurrent = "@param __current The Current object for the invocation."; + } + if(amd) + { + writeDocCommentAsync(out, *r, InParam, extraCurrent); + } + else + { + writeDocComment(out, *r, deprecateReason, extraCurrent); + } + out << nl << retS << ' ' << (amd ? opname + "_async" : fixKwd(opname)) << spar << params; + if(!noCurrent && !p->isLocal()) + { + out << "Ice.Current __current"; + } + out << epar; + if(op->hasMetaData("UserException")) + { + out.inc(); + out << nl << "throws Ice.UserException"; + out.dec(); + } + else + { + writeThrowsClause(package, throws); + } + out << ';'; + } + + out << eb; + + close(); +} + +Slice::GenCompat::TieVisitor::TieVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::TieVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string name = p->name(); + ClassList bases = p->bases(); + string package = getPackage(p); + string absolute = getAbsolute(p, "", "_", "Tie"); + string opIntfName = "Operations"; + if(p->isLocal()) + { + opIntfName += "NC"; + } + + // + // Don't generate a TIE class for a non-abstract class + // + if(!p->isAbstract()) + { + return false; + } + + open(absolute, p->file()); + + Output& out = output(); + + // + // Generate the TIE class + // + out << sp << nl << "public class " << '_' << name << "Tie"; + if(p->isInterface()) + { + if(p->isLocal()) + { + out << " implements " << fixKwd(name) << ", Ice.TieBase"; + } + else + { + out << " extends " << '_' << name << "Disp implements Ice.TieBase"; + } + } + else + { + out << " extends " << fixKwd(name) << " implements Ice.TieBase"; + } + + out << sb; + + out << sp << nl << "public _" << name << "Tie()"; + out << sb; + out << eb; + + out << sp << nl << "public _" << name << "Tie(" << '_' << name << opIntfName << " delegate)"; + out << sb; + out << nl << "_ice_delegate = delegate;"; + out << eb; + + out << sp << nl << "public java.lang.Object ice_delegate()"; + out << sb; + out << nl << "return _ice_delegate;"; + out << eb; + + out << sp << nl << "public void ice_delegate(java.lang.Object delegate)"; + out << sb; + out << nl << "_ice_delegate = (_" << name << opIntfName << ")delegate;"; + out << eb; + + out << sp << nl << "public boolean equals(java.lang.Object rhs)"; + out << sb; + out << nl << "if(this == rhs)"; + out << sb; + out << nl << "return true;"; + out << eb; + out << nl << "if(!(rhs instanceof " << '_' << name << "Tie))"; + out << sb; + out << nl << "return false;"; + out << eb; + out << sp << nl << "return _ice_delegate.equals(((" << '_' << name << "Tie)rhs)._ice_delegate);"; + out << eb; + + out << sp << nl << "public int hashCode()"; + out << sb; + out << nl << "return _ice_delegate.hashCode();"; + out << eb; + + if(p->isLocal()) + { + out << sp << nl << "public _" << name << "Tie clone()"; + out.inc(); + out << nl << "throws java.lang.CloneNotSupportedException"; + out.dec(); + out << sb; + out << nl << "return (_" << name << "Tie)super.clone();"; + out << eb; + } + + OperationList ops = p->allOperations(); + for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + { + ContainerPtr container = (*r)->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + const bool hasAMD = cl->hasMetaData("amd") || (*r)->hasMetaData("amd"); + const bool optionalMapping = useOptionalMapping(*r); + + string opName = hasAMD ? (*r)->name() + "_async" : fixKwd((*r)->name()); + + TypePtr ret = (*r)->returnType(); + string retS = typeToString(ret, TypeModeReturn, package, (*r)->getMetaData(), true, + optionalMapping && (*r)->returnIsOptional()); + + vector<string> params; + vector<string> args; + if(hasAMD) + { + params = getParamsAsync((*r), package, true, true); + args = getArgsAsync(*r); + } + else + { + params = getParams((*r), package, false, optionalMapping); + args = getArgs(*r); + } + + string deprecateReason = getDeprecateReason(*r, cl, "operation"); + + out << sp; + if(!deprecateReason.empty()) + { + out << nl << "@Deprecated"; + out << nl << "@SuppressWarnings(\"deprecation\")"; + } + out << nl << "public " << (hasAMD ? string("void") : retS) << ' ' << opName << spar << params; + if(!p->isLocal()) + { + out << "Ice.Current __current"; + } + out << epar; + + if((*r)->hasMetaData("UserException")) + { + out.inc(); + out << nl << "throws Ice.UserException"; + out.dec(); + } + else + { + ExceptionList throws = (*r)->throws(); + throws.sort(); + throws.unique(); + writeThrowsClause(package, throws); + } + out << sb; + out << nl; + if(ret && !hasAMD) + { + out << "return "; + } + out << "_ice_delegate." << opName << spar << args; + if(!p->isLocal()) + { + out << "__current"; + } + out << epar << ';'; + out << eb; + } + + out << sp << nl << "private " << '_' << name << opIntfName << " _ice_delegate;"; + out << sp << nl << "public static final long serialVersionUID = "; + string serialVersionUID; + if(p->findMetaData("java:serialVersionUID", serialVersionUID)) + { + string::size_type pos = serialVersionUID.rfind(":") + 1; + if(pos == string::npos) + { + ostringstream os; + os << "ignoring invalid serialVersionUID for class `" << p->scoped() << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + else + { + Int64 v = 0; + serialVersionUID = serialVersionUID.substr(pos); + if(serialVersionUID != "0") + { + if(!stringToInt64(serialVersionUID, v)) // conversion error + { + ostringstream os; + os << "ignoring invalid serialVersionUID for class `" << p->scoped() + << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + } + out << v; + } + } + else + { + out << computeSerialVersionUUID(p); + } + out << "L;"; + out << eb; + close(); + + return false; +} + +Slice::GenCompat::PackageVisitor::PackageVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::PackageVisitor::visitModuleStart(const ModulePtr& p) +{ + string prefix = getPackagePrefix(p); + if(!prefix.empty()) + { + string markerClass = prefix + "." + fixKwd(p->name()) + "._Marker"; + open(markerClass, p->file()); + + Output& out = output(); + + out << sp << nl << "interface _Marker"; + out << sb; + out << eb; + + close(); + } + return false; +} + +Slice::GenCompat::TypesVisitor::TypesVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string name = p->name(); + ClassList bases = p->bases(); + ClassDefPtr baseClass; + if(!bases.empty() && !bases.front()->isInterface()) + { + baseClass = bases.front(); + } + + string package = getPackage(p); + string absolute = getAbsolute(p); + DataMemberList members = p->dataMembers(); + DataMemberList allDataMembers = p->allDataMembers(); + + open(absolute, p->file()); + + Output& out = output(); + + // + // Slice interfaces map to Java interfaces. + // + out << sp; + writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); + if(p->isInterface()) + { + out << nl << "public interface " << fixKwd(name); + if(!p->isLocal()) + { + out << " extends "; + out.useCurrentPosAsIndent(); + out << "Ice.Object"; + out << "," << nl << '_' << name; + out << "Operations, _" << name << "OperationsNC"; + } + else + { + if(!bases.empty()) + { + out << " extends "; + } + out.useCurrentPosAsIndent(); + } + + ClassList::const_iterator q = bases.begin(); + if(p->isLocal() && q != bases.end()) + { + out << getAbsolute(*q++, package); + } + while(q != bases.end()) + { + out << ',' << nl << getAbsolute(*q, package); + q++; + } + out.restoreIndent(); + } + else + { + out << nl << "public "; + if(p->allOperations().size() > 0) // Don't use isAbstract() - see bug 3739 + { + out << "abstract "; + } + out << "class " << fixKwd(name); + out.useCurrentPosAsIndent(); + + StringList implements; + bool implementsOnNewLine = true; + + if(bases.empty() || bases.front()->isInterface()) + { + if(p->isLocal()) + { + implementsOnNewLine = false; + implements.push_back("java.lang.Cloneable"); + } + else + { + out << " extends Ice.ObjectImpl"; + } + } + else + { + out << " extends "; + out << getAbsolute(baseClass, package); + bases.pop_front(); + } + + // + // Implement interfaces + // + + if(p->isAbstract()) + { + if(!p->isLocal()) + { + implements.push_back("_" + name + "Operations"); + implements.push_back("_" + name + "OperationsNC"); + } + } + if(!bases.empty()) + { + for(ClassList::const_iterator q = bases.begin(); q != bases.end();) + { + implements.push_back(getAbsolute(*q, package)); + q++; + } + } + + if(!implements.empty()) + { + if(implementsOnNewLine) + { + out << nl; + } + + out << " implements "; + out.useCurrentPosAsIndent(); + + for(StringList::const_iterator q = implements.begin(); q != implements.end();) + { + if(q != implements.begin()) + { + out << ',' << nl; + } + out << *q; + q++; + } + + out.restoreIndent(); + } + + out.restoreIndent(); + } + + out << sb; + + // + // For local classes and interfaces, we don't use the OperationsNC interface. + // Instead, we generate the operation signatures directly into the class + // or interface. + // + if(p->isLocal()) + { + OperationList ops = p->operations(); + for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = *r; + const ContainerPtr container = op->container(); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + const string opname = op->name(); + const bool optionalMapping = useOptionalMapping(op); + + const TypePtr ret = op->returnType(); + vector<string> params = getParams(op, package, true, optionalMapping); + + string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, + optionalMapping && op->returnIsOptional()); + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + out << sp; + + writeDocComment(out, *r, getDeprecateReason(*r, p, "operation")); + out << nl; + if(!p->isInterface()) + { + out << "public abstract "; + } + out << retS << ' ' << fixKwd(opname) << spar << params << epar; + if(op->hasMetaData("UserException")) + { + out.inc(); + out << nl << "throws Ice.UserException"; + out.dec(); + } + else + { + writeThrowsClause(package, throws); + } + out << ';'; + + // + // Generate asynchronous API for local operations marked with "async-oneway" metadata. + // + if(p->hasMetaData("async-oneway") || op->hasMetaData("async-oneway")) + { + vector<string> inParams = getInOutParams(op, package, InParam, true, true); + + out << sp; + writeDocCommentAMI(out, op, InParam); + out << nl; + if(!p->isInterface()) + { + out << "public abstract "; + } + out << "Ice.AsyncResult begin_" << opname << spar << inParams << epar << ';'; + + out << sp; + writeDocCommentAMI(out, op, InParam); + out << nl; + if(!p->isInterface()) + { + out << "public abstract "; + } + out << "Ice.AsyncResult begin_" << opname << spar << inParams << "Ice.Callback __cb" << epar << ';'; + + out << sp; + writeDocCommentAMI(out, op, InParam); + out << nl; + if(!p->isInterface()) + { + out << "public abstract "; + } + string cb = "Callback_" + name + "_" + opname + " __cb"; + out << "Ice.AsyncResult begin_" << opname << spar << inParams << cb << epar << ';'; + + + out << sp; + writeDocCommentAMI(out, op, InParam); + out << nl; + if(!p->isInterface()) + { + out << "public abstract "; + } + out << nl << "Ice.AsyncResult begin_" << opname; + writeParamList(out, getParamsAsyncLambda(op, package, false, true)); + out << ';'; + + vector<string> outParams = getInOutParams(op, package, OutParam, true, true); + out << sp; + writeDocCommentAMI(out, op, OutParam); + out << nl; + if(!p->isInterface()) + { + out << "public abstract "; + } + + out << retS << " end_" << opname << spar << outParams << "Ice.AsyncResult __result" << epar << ';'; + } + } + } + + if(!p->isInterface() && !allDataMembers.empty()) + { + bool hasOptionalMembers = false; + bool hasRequiredMembers = false; + + for(DataMemberList::const_iterator d = allDataMembers.begin(); d != allDataMembers.end(); ++d) + { + if((*d)->optional()) + { + hasOptionalMembers = true; + } + else + { + hasRequiredMembers = true; + } + } + + // + // Default constructor. + // + out << sp; + out << nl << "public " << fixKwd(name) << "()"; + out << sb; + if(baseClass) + { + out << nl << "super();"; + } + writeDataMemberInitializers(out, members, package); + out << eb; + + // + // A method cannot have more than 255 parameters (including the implicit "this" argument). + // + if(allDataMembers.size() < 255) + { + DataMemberList baseDataMembers; + if(baseClass) + { + baseDataMembers = baseClass->allDataMembers(); + } + + if(hasRequiredMembers && hasOptionalMembers) + { + // + // Generate a constructor accepting parameters for just the required members. + // + out << sp << nl << "public " << fixKwd(name) << spar; + vector<string> paramDecl; + for(DataMemberList::const_iterator d = allDataMembers.begin(); d != allDataMembers.end(); ++d) + { + if(!(*d)->optional()) + { + string memberName = fixKwd((*d)->name()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + paramDecl.push_back(memberType + " " + memberName); + } + } + out << paramDecl << epar; + out << sb; + if(!baseDataMembers.empty()) + { + bool hasBaseRequired = false; + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + if(!(*d)->optional()) + { + hasBaseRequired = true; + break; + } + } + if(hasBaseRequired) + { + out << nl << "super" << spar; + vector<string> baseParamNames; + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + if(!(*d)->optional()) + { + baseParamNames.push_back(fixKwd((*d)->name())); + } + } + out << baseParamNames << epar << ';'; + } + } + + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + string paramName = fixKwd((*d)->name()); + out << nl << "this." << paramName << " = " << paramName << ';'; + } + } + writeDataMemberInitializers(out, p->orderedOptionalDataMembers(), package); + out << eb; + } + + // + // Generate a constructor accepting parameters for all members. + // + out << sp << nl << "public " << fixKwd(name) << spar; + vector<string> paramDecl; + for(DataMemberList::const_iterator d = allDataMembers.begin(); d != allDataMembers.end(); ++d) + { + string memberName = fixKwd((*d)->name()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + paramDecl.push_back(memberType + " " + memberName); + } + out << paramDecl << epar; + out << sb; + if(baseClass && allDataMembers.size() != members.size()) + { + out << nl << "super" << spar; + vector<string> baseParamNames; + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + baseParamNames.push_back(fixKwd((*d)->name())); + } + out << baseParamNames << epar << ';'; + } + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + string paramName = fixKwd((*d)->name()); + if((*d)->optional()) + { + string capName = paramName; + capName[0] = toupper(static_cast<unsigned char>(capName[0])); + out << nl << "set" << capName << '(' << paramName << ");"; + } + else + { + out << nl << "this." << paramName << " = " << paramName << ';'; + } + } + out << eb; + } + } + + // + // Default factory for non-abstract classes. + // + if(!p->isInterface() && p->allOperations().size() == 0 && !p->isLocal()) + { + out << sp; + out << nl << "private static class __F implements Ice.ValueFactory"; + out << sb; + out << nl << "public Ice.Object create(String type)"; + out << sb; + out << nl << "assert(type.equals(ice_staticId()));"; + out << nl << "return new " << fixKwd(name) << "();"; + out << eb; + out << eb; + out << nl << "private static Ice.ValueFactory _factory = new __F();"; + out << sp; + out << nl << "public static Ice.ValueFactory" << nl << "ice_factory()"; + out << sb; + out << nl << "return _factory;"; + out << eb; + } + + // + // Marshalling & dispatch support. + // + if(!p->isInterface() && !p->isLocal()) + { + writeDispatchAndMarshalling(out, p); + } + + return true; +} + +void +Slice::GenCompat::TypesVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + Output& out = output(); + + ClassList bases = p->bases(); + ClassDefPtr baseClass; + if(!bases.empty() && !bases.front()->isInterface()) + { + baseClass = bases.front(); + } + + string name = fixKwd(p->name()); + + if(!p->isInterface()) + { + out << sp << nl << "public " << name << nl << "clone()"; + out << sb; + + if(p->isLocal() && !baseClass) + { + out << nl << name << " c = null;"; + out << nl << "try"; + out << sb; + out << nl << "c = (" << name << ")super.clone();"; + out << eb; + out << nl << "catch(CloneNotSupportedException ex)"; + out << sb; + out << nl << "assert false; // impossible"; + out << eb; + out << nl << "return c;"; + + } + else + { + out << nl << "return (" << name << ")super.clone();"; + } + out << eb; + } + + if(p->isInterface() && !p->isLocal()) + { + out << sp << nl << "public static final String ice_staticId = \"" << p->scoped() << "\";"; + } + + out << sp << nl << "public static final long serialVersionUID = "; + string serialVersionUID; + if(p->findMetaData("java:serialVersionUID", serialVersionUID)) + { + string::size_type pos = serialVersionUID.rfind(":") + 1; + if(pos == string::npos) + { + ostringstream os; + os << "ignoring invalid serialVersionUID for class `" << p->scoped() << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + else + { + Int64 v = 0; + serialVersionUID = serialVersionUID.substr(pos); + if(serialVersionUID != "0") + { + if(!stringToInt64(serialVersionUID, v)) // conversion error + { + ostringstream os; + os << "ignoring invalid serialVersionUID for class `" << p->scoped() + << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + } + out << v; + } + } + else + { + out << computeSerialVersionUUID(p); + } + out << "L;"; + out << eb; + close(); +} + +bool +Slice::GenCompat::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + string name = fixKwd(p->name()); + string scoped = p->scoped(); + ExceptionPtr base = p->base(); + string package = getPackage(p); + string absolute = getAbsolute(p); + DataMemberList members = p->dataMembers(); + DataMemberList allDataMembers = p->allDataMembers(); + + open(absolute, p->file()); + + Output& out = output(); + + out << sp; + + writeDocComment(out, p, getDeprecateReason(p, 0, "type")); + + out << nl << "public class " << name << " extends "; + + if(!base) + { + if(p->isLocal()) + { + out << "Ice.LocalException"; + } + else + { + out << "Ice.UserException"; + } + } + else + { + out << getAbsolute(base, package); + } + out << sb; + + // + // Default constructor. + // + out << sp; + out << nl << "public " << name << "()"; + out << sb; + if(base) + { + out << nl << "super();"; + } + writeDataMemberInitializers(out, members, package); + out << eb; + + out << sp; + out << nl << "public " << name << "(Throwable __cause)"; + out << sb; + out << nl << "super(__cause);"; + writeDataMemberInitializers(out, members, package); + out << eb; + + bool hasOptionalMembers = false; + bool hasRequiredMembers = false; + for(DataMemberList::const_iterator d = allDataMembers.begin(); d != allDataMembers.end(); ++d) + { + if((*d)->optional()) + { + hasOptionalMembers = true; + } + else + { + hasRequiredMembers = true; + } + } + + if(!allDataMembers.empty()) + { + DataMemberList baseDataMembers; + if(base) + { + baseDataMembers = base->allDataMembers(); + } + + // + // A method cannot have more than 255 parameters (including the implicit "this" argument). + // + if(allDataMembers.size() < 255) + { + if(hasRequiredMembers && hasOptionalMembers) + { + bool hasBaseRequired = false; + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + if(!(*d)->optional()) + { + hasBaseRequired = true; + break; + } + } + + DataMemberList optionalMembers = p->orderedOptionalDataMembers(); + + // + // Generate a constructor accepting parameters for just the required members. + // + out << sp << nl << "public " << name << spar; + vector<string> paramDecl; + for(DataMemberList::const_iterator d = allDataMembers.begin(); d != allDataMembers.end(); ++d) + { + if(!(*d)->optional()) + { + string memberName = fixKwd((*d)->name()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + paramDecl.push_back(memberType + " " + memberName); + } + } + out << paramDecl << epar; + out << sb; + if(!baseDataMembers.empty()) + { + if(hasBaseRequired) + { + out << nl << "super" << spar; + vector<string> baseParamNames; + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + if(!(*d)->optional()) + { + baseParamNames.push_back(fixKwd((*d)->name())); + } + } + out << baseParamNames << epar << ';'; + } + } + + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + string paramName = fixKwd((*d)->name()); + out << nl << "this." << paramName << " = " << paramName << ';'; + } + } + writeDataMemberInitializers(out, optionalMembers, package); + out << eb; + + // + // Create constructor that takes all data members plus a Throwable. + // + if(allDataMembers.size() < 254) + { + paramDecl.push_back("Throwable __cause"); + out << sp << nl << "public " << name << spar; + out << paramDecl << epar; + out << sb; + if(hasBaseRequired) + { + out << nl << "super" << spar; + vector<string> baseParamNames; + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + if(!(*d)->optional()) + { + baseParamNames.push_back(fixKwd((*d)->name())); + } + } + baseParamNames.push_back("__cause"); + out << baseParamNames << epar << ';'; + } + else + { + out << nl << "super(__cause);"; + } + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + string paramName = fixKwd((*d)->name()); + out << nl << "this." << paramName << " = " << paramName << ';'; + } + } + writeDataMemberInitializers(out, optionalMembers, package); + out << eb; + } + } + + out << sp << nl << "public " << name << spar; + vector<string> paramDecl; + for(DataMemberList::const_iterator d = allDataMembers.begin(); d != allDataMembers.end(); ++d) + { + string memberName = fixKwd((*d)->name()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + paramDecl.push_back(memberType + " " + memberName); + } + out << paramDecl << epar; + out << sb; + if(base && allDataMembers.size() != members.size()) + { + out << nl << "super" << spar; + vector<string> baseParamNames; + DataMemberList baseDataMembers = base->allDataMembers(); + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + baseParamNames.push_back(fixKwd((*d)->name())); + } + + out << baseParamNames << epar << ';'; + } + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + string paramName = fixKwd((*d)->name()); + if((*d)->optional()) + { + string capName = paramName; + capName[0] = toupper(static_cast<unsigned char>(capName[0])); + out << nl << "set" << capName << '(' << paramName << ");"; + } + else + { + out << nl << "this." << paramName << " = " << paramName << ';'; + } + } + out << eb; + + // + // Create constructor that takes all data members plus a Throwable + // + if(allDataMembers.size() < 254) + { + paramDecl.push_back("Throwable __cause"); + out << sp << nl << "public " << name << spar; + out << paramDecl << epar; + out << sb; + if(!base) + { + out << nl << "super(__cause);"; + } + else + { + out << nl << "super" << spar; + vector<string> baseParamNames; + DataMemberList baseDataMembers = base->allDataMembers(); + for(DataMemberList::const_iterator d = baseDataMembers.begin(); d != baseDataMembers.end(); ++d) + { + baseParamNames.push_back(fixKwd((*d)->name())); + } + baseParamNames.push_back("__cause"); + out << baseParamNames << epar << ';'; + } + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + string paramName = fixKwd((*d)->name()); + if((*d)->optional()) + { + string capName = paramName; + capName[0] = toupper(static_cast<unsigned char>(capName[0])); + out << nl << "set" << capName << '(' << paramName << ");"; + } + else + { + out << nl << "this." << paramName << " = " << paramName << ';'; + } + } + out << eb; + } + } + } + + out << sp << nl << "public String" << nl << "ice_id()"; + out << sb; + out << nl << "return \"" << scoped << "\";"; + out << eb; + + return true; +} + +void +Slice::GenCompat::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) +{ + Output& out = output(); + + if(!p->isLocal()) + { + string name = fixKwd(p->name()); + string scoped = p->scoped(); + string package = getPackage(p); + ExceptionPtr base = p->base(); + bool basePreserved = p->inheritsMetaData("preserve-slice"); + bool preserved = p->hasMetaData("preserve-slice"); + + DataMemberList members = p->dataMembers(); + DataMemberList optionalMembers = p->orderedOptionalDataMembers(); + int iter; + + if(preserved && !basePreserved) + { + + out << sp << nl << "public void" << nl << "__write(Ice.OutputStream __os)"; + out << sb; + out << nl << "__os.startException(__slicedData);"; + out << nl << "__writeImpl(__os);"; + out << nl << "__os.endException();"; + out << eb; + + out << sp << nl << "public void" << nl << "__read(Ice.InputStream __is)"; + out << sb; + out << nl << "__is.startException();"; + out << nl << "__readImpl(__is);"; + out << nl << "__slicedData = __is.endException(true);"; + out << eb; + } + + out << sp << nl << "protected void" << nl << "__writeImpl(Ice.OutputStream __os)"; + out << sb; + out << nl << "__os.startSlice(\"" << scoped << "\", -1, " << (!base ? "true" : "false") << ");"; + iter = 0; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + writeMarshalDataMember(out, package, *d, iter); + } + } + for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) + { + writeMarshalDataMember(out, package, *d, iter); + } + out << nl << "__os.endSlice();"; + if(base) + { + out << nl << "super.__writeImpl(__os);"; + } + out << eb; + + DataMemberList classMembers = p->classDataMembers(); + DataMemberList allClassMembers = p->allClassDataMembers(); + + if(classMembers.size() != 0) + { + writePatcher(out, package, classMembers, optionalMembers); + } + out << sp << nl << "protected void" << nl << "__readImpl(Ice.InputStream __is)"; + out << sb; + out << nl << "__is.startSlice();"; + iter = 0; + int patchIter = 0; + const bool needCustomPatcher = classMembers.size() > 1; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + if(!(*d)->optional()) + { + writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + } + } + for(DataMemberList::const_iterator d = optionalMembers.begin(); d != optionalMembers.end(); ++d) + { + writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + } + out << nl << "__is.endSlice();"; + if(base) + { + out << nl << "super.__readImpl(__is);"; + } + out << eb; + + if(p->usesClasses(false)) + { + if(!base || (base && !base->usesClasses(false))) + { + out << sp << nl << "public boolean" << nl << "__usesClasses()"; + out << sb; + out << nl << "return true;"; + out << eb; + } + } + + if(preserved && !basePreserved) + { + out << sp << nl << "protected Ice.SlicedData __slicedData;"; + } + } + + out << sp << nl << "public static final long serialVersionUID = "; + string serialVersionUID; + if(p->findMetaData("java:serialVersionUID", serialVersionUID)) + { + string::size_type pos = serialVersionUID.rfind(":") + 1; + if(pos == string::npos) + { + ostringstream os; + os << "ignoring invalid serialVersionUID for exception `" << p->scoped() << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + else + { + Int64 v = 0; + serialVersionUID = serialVersionUID.substr(pos); + if(serialVersionUID != "0") + { + if(!stringToInt64(serialVersionUID, v)) // conversion error + { + ostringstream os; + os << "ignoring invalid serialVersionUID for exception `" << p->scoped() + << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + } + out << v; + } + } + else + { + out << computeSerialVersionUUID(p); + } + out << "L;"; + + out << eb; + close(); +} + +bool +Slice::GenCompat::TypesVisitor::visitStructStart(const StructPtr& p) +{ + string name = fixKwd(p->name()); + string absolute = getAbsolute(p); + + open(absolute, p->file()); + + Output& out = output(); + + out << sp; + + writeDocComment(out, p, getDeprecateReason(p, 0, "type")); + + out << nl << "public class " << name << " implements java.lang.Cloneable"; + if(!p->isLocal()) + { + out << ", java.io.Serializable"; + } + out << sb; + + return true; +} + +void +Slice::GenCompat::TypesVisitor::visitStructEnd(const StructPtr& p) +{ + string package = getPackage(p); + + Output& out = output(); + + DataMemberList members = p->dataMembers(); + int iter; + + string name = fixKwd(p->name()); + string typeS = typeToString(p, TypeModeIn, package); + + out << sp << nl << "public " << name << "()"; + out << sb; + writeDataMemberInitializers(out, members, package); + out << eb; + + // + // A method cannot have more than 255 parameters (including the implicit "this" argument). + // + if(members.size() < 255) + { + vector<string> paramDecl; + vector<string> paramNames; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + string memberName = fixKwd((*d)->name()); + string memberType = typeToString((*d)->type(), TypeModeMember, package, (*d)->getMetaData()); + paramDecl.push_back(memberType + " " + memberName); + paramNames.push_back(memberName); + } + + out << sp << nl << "public " << name << spar << paramDecl << epar; + out << sb; + for(vector<string>::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) + { + out << nl << "this." << *i << " = " << *i << ';'; + } + out << eb; + } + + out << sp << nl << "public boolean" << nl << "equals(java.lang.Object rhs)"; + out << sb; + out << nl << "if(this == rhs)"; + out << sb; + out << nl << "return true;"; + out << eb; + out << nl << typeS << " _r = null;"; + out << nl << "if(rhs instanceof " << typeS << ")"; + out << sb; + out << nl << "_r = (" << typeS << ")rhs;"; + out << eb; + out << sp << nl << "if(_r != null)"; + out << sb; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + string memberName = fixKwd((*d)->name()); + BuiltinPtr b = BuiltinPtr::dynamicCast((*d)->type()); + if(b) + { + switch(b->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + { + out << nl << "if(" << memberName << " != _r." << memberName << ')'; + out << sb; + out << nl << "return false;"; + out << eb; + break; + } + + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + out << nl << "if(" << memberName << " != _r." << memberName << ')'; + out << sb; + out << nl << "if(" << memberName << " == null || _r." << memberName << " == null || !" + << memberName << ".equals(_r." << memberName << "))"; + out << sb; + out << nl << "return false;"; + out << eb; + out << eb; + break; + } + } + } + else + { + // + // We treat sequences differently because the native equals() method for + // a Java array does not perform a deep comparison. If the mapped type + // is not overridden via metadata, we use the helper method + // java.util.Arrays.equals() to compare native arrays. + // + // For all other types, we can use the native equals() method. + // + SequencePtr seq = SequencePtr::dynamicCast((*d)->type()); + if(seq) + { + if(hasTypeMetaData(seq, (*d)->getMetaData())) + { + out << nl << "if(" << memberName << " != _r." << memberName << ')'; + out << sb; + out << nl << "if(" << memberName << " == null || _r." << memberName << " == null || !" + << memberName << ".equals(_r." << memberName << "))"; + out << sb; + out << nl << "return false;"; + out << eb; + out << eb; + } + else + { + // + // Arrays.equals() handles null values. + // + out << nl << "if(!java.util.Arrays.equals(" << memberName << ", _r." << memberName << "))"; + out << sb; + out << nl << "return false;"; + out << eb; + } + } + else + { + out << nl << "if(" << memberName << " != _r." << memberName << ')'; + out << sb; + out << nl << "if(" << memberName << " == null || _r." << memberName << " == null || !" + << memberName << ".equals(_r." << memberName << "))"; + out << sb; + out << nl << "return false;"; + out << eb; + out << eb; + } + } + } + out << sp << nl << "return true;"; + out << eb; + out << sp << nl << "return false;"; + out << eb; + + out << sp << nl << "public int" << nl << "hashCode()"; + out << sb; + out << nl << "int __h = 5381;"; + out << nl << "__h = IceInternal.HashUtil.hashAdd(__h, \"" << p->scoped() << "\");"; + iter = 0; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + string memberName = fixKwd((*d)->name()); + out << nl << "__h = IceInternal.HashUtil.hashAdd(__h, " << memberName << ");"; + } + out << nl << "return __h;"; + out << eb; + + out << sp << nl << "public " << name << nl << "clone()"; + out << sb; + out << nl << name << " c = null;"; + out << nl << "try"; + out << sb; + out << nl << "c = (" << name << ")super.clone();"; + out << eb; + out << nl << "catch(CloneNotSupportedException ex)"; + out << sb; + out << nl << "assert false; // impossible"; + out << eb; + out << nl << "return c;"; + out << eb; + + if(!p->isLocal()) + { + out << sp << nl << "public void" << nl << "__write(Ice.OutputStream __os)"; + out << sb; + iter = 0; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + writeMarshalDataMember(out, package, *d, iter); + } + out << eb; + + DataMemberList classMembers = p->classDataMembers(); + + if(classMembers.size() != 0) + { + writePatcher(out, package, classMembers, DataMemberList()); + } + + out << sp << nl << "public void" << nl << "__read(Ice.InputStream __is)"; + out << sb; + iter = 0; + int patchIter = 0; + const bool needCustomPatcher = classMembers.size() > 1; + for(DataMemberList::const_iterator d = members.begin(); d != members.end(); ++d) + { + writeUnmarshalDataMember(out, package, *d, iter, needCustomPatcher, patchIter); + } + out << eb; + + out << sp << nl << "static public void" << nl << "write(Ice.OutputStream __os, " << name << " __v)"; + out << sb; + out << nl << "if(__v == null)"; + out << sb; + out << nl << "__nullMarshalValue.__write(__os);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "__v.__write(__os);"; + out << eb; + out << eb; + + out << sp << nl << "static public " << name << nl << "read(Ice.InputStream __is, " << name << " __v)"; + out << sb; + out << nl << "if(__v == null)"; + out << sb; + out << nl << " __v = new " << name << "();"; + out << eb; + out << nl << "__v.__read(__is);"; + out << nl << "return __v;"; + out << eb; + + out << nl << nl << "private static final " << name << " __nullMarshalValue = new " << name << "();"; + } + + out << sp << nl << "public static final long serialVersionUID = "; + string serialVersionUID; + if(p->findMetaData("java:serialVersionUID", serialVersionUID)) + { + string::size_type pos = serialVersionUID.rfind(":") + 1; + if(pos == string::npos) + { + ostringstream os; + os << "ignoring invalid serialVersionUID for struct `" << p->scoped() << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + else + { + Int64 v = 0; + serialVersionUID = serialVersionUID.substr(pos); + if(serialVersionUID != "0") + { + if(!stringToInt64(serialVersionUID, v)) // conversion error + { + ostringstream os; + os << "ignoring invalid serialVersionUID for struct `" << p->scoped() + << "'; generating default value"; + emitWarning("", "", os.str()); + out << computeSerialVersionUUID(p); + } + } + out << v; + } + } + else + { + out << computeSerialVersionUUID(p); + } + out << "L;"; + + out << eb; + close(); +} + +void +Slice::GenCompat::TypesVisitor::visitDataMember(const DataMemberPtr& p) +{ + string name = fixKwd(p->name()); + ContainerPtr container = p->container(); + ContainedPtr contained = ContainedPtr::dynamicCast(container); + StringList metaData = p->getMetaData(); + TypePtr type = p->type(); + string s = typeToString(type, TypeModeMember, getPackage(contained), metaData); + Output& out = output(); + const bool optional = p->optional(); + const bool getSet = p->hasMetaData(_getSetMetaData) || contained->hasMetaData(_getSetMetaData); + + out << sp; + + string deprecateReason = getDeprecateReason(p, contained, "member"); + writeDocComment(out, p, deprecateReason); + + // + // Access visibility for class data members can be controlled by metadata. + // If none is specified, the default is public. + // + if(contained->containedType() == Contained::ContainedTypeClass && + (p->hasMetaData("protected") || contained->hasMetaData("protected"))) + { + out << nl << "protected " << s << ' ' << name << ';'; + } + else if(optional) + { + out << nl << "private " << s << ' ' << name << ';'; + } + else + { + out << nl << "public " << s << ' ' << name << ';'; + } + + if(optional) + { + out << nl << "private boolean __has_" << p->name() << ';'; + } + + // + // Getter/Setter. + // + if(getSet || optional) + { + string capName = p->name(); + capName[0] = toupper(static_cast<unsigned char>(capName[0])); + + // + // If container is a class, get all of its operations so that we can check for conflicts. + // + OperationList ops; + string file, line; + ClassDefPtr cls = ClassDefPtr::dynamicCast(container); + if(cls) + { + ops = cls->allOperations(); + file = p->file(); + line = p->line(); + if(!validateMethod(ops, "get" + capName, 0, file, line) || + !validateMethod(ops, "set" + capName, 1, file, line)) + { + return; + } + if(optional && + (!validateMethod(ops, "has" + capName, 0, file, line) || + !validateMethod(ops, "clear" + capName, 0, file, line) || + !validateMethod(ops, "optional" + capName, 0, file, line))) + { + return; + } + } + + // + // Getter. + // + out << sp; + writeDocComment(out, p, deprecateReason); + out << nl << "public " << s + << nl << "get" << capName << "()"; + out << sb; + if(optional) + { + out << nl << "if(!__has_" << p->name() << ')'; + out << sb; + out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << eb; + } + out << nl << "return " << name << ';'; + out << eb; + + // + // Setter. + // + out << sp; + writeDocComment(out, p, deprecateReason); + out << nl << "public void" + << nl << "set" << capName << '(' << s << " _" << name << ')'; + out << sb; + if(optional) + { + out << nl << "__has_" << p->name() << " = true;"; + } + out << nl << name << " = _" << name << ';'; + out << eb; + + // + // Generate hasFoo and clearFoo for optional member. + // + if(optional) + { + out << sp; + writeDocComment(out, p, deprecateReason); + out << nl << "public boolean" + << nl << "has" << capName << "()"; + out << sb; + out << nl << "return __has_" << p->name() << ';'; + out << eb; + + out << sp; + writeDocComment(out, p, deprecateReason); + out << nl << "public void" + << nl << "clear" << capName << "()"; + out << sb; + out << nl << "__has_" << p->name() << " = false;"; + out << eb; + + const string optType = typeToString(type, TypeModeMember, getPackage(contained), metaData, true, true); + + out << sp; + writeDocComment(out, p, deprecateReason); + out << nl << "public void" + << nl << "optional" << capName << '(' << optType << " __v)"; + out << sb; + out << nl << "if(__v == null || !__v.isSet())"; + out << sb; + out << nl << "__has_" << p->name() << " = false;"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "__has_" << p->name() << " = true;"; + out << nl << name << " = __v.get();"; + out << eb; + out << eb; + + out << sp; + writeDocComment(out, p, deprecateReason); + out << nl << "public " << optType + << nl << "optional" << capName << "()"; + out << sb; + out << nl << "if(__has_" << p->name() << ')'; + out << sb; + out << nl << "return new " << optType << '(' << name << ");"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "return new " << optType << "();"; + out << eb; + out << eb; + } + + // + // Check for bool type. + // + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b && b->kind() == Builtin::KindBool) + { + if(cls && !validateMethod(ops, "is" + capName, 0, file, line)) + { + return; + } + out << sp; + if(!deprecateReason.empty()) + { + out << nl << "/**"; + out << nl << " * @deprecated " << deprecateReason; + out << nl << " **/"; + } + out << nl << "public boolean"; + out << nl << "is" << capName << "()"; + out << sb; + if(optional) + { + out << nl << "if(!__has_" << p->name() << ')'; + out << sb; + out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << eb; + } + out << nl << "return " << name << ';'; + out << eb; + } + + // + // Check for unmodified sequence type and emit indexing methods. + // + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + if(!hasTypeMetaData(seq, metaData)) + { + if(cls && + (!validateMethod(ops, "get" + capName, 1, file, line) || + !validateMethod(ops, "set" + capName, 2, file, line))) + { + return; + } + + string elem = typeToString(seq->type(), TypeModeMember, getPackage(contained)); + + // + // Indexed getter. + // + out << sp; + if(!deprecateReason.empty()) + { + out << nl << "/**"; + out << nl << " * @deprecated " << deprecateReason; + out << nl << " **/"; + } + out << nl << "public " << elem; + out << nl << "get" << capName << "(int _index)"; + out << sb; + if(optional) + { + out << nl << "if(!__has_" << p->name() << ')'; + out << sb; + out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << eb; + } + out << nl << "return " << name << "[_index];"; + out << eb; + + // + // Indexed setter. + // + out << sp; + if(!deprecateReason.empty()) + { + out << nl << "/**"; + out << nl << " * @deprecated " << deprecateReason; + out << nl << " **/"; + } + out << nl << "public void"; + out << nl << "set" << capName << "(int _index, " << elem << " _val)"; + out << sb; + if(optional) + { + out << nl << "if(!__has_" << p->name() << ')'; + out << sb; + out << nl << "throw new java.lang.IllegalStateException(\"" << name << " is not set\");"; + out << eb; + } + out << nl << name << "[_index] = _val;"; + out << eb; + } + } + } +} + +void +Slice::GenCompat::TypesVisitor::visitEnum(const EnumPtr& p) +{ + string name = fixKwd(p->name()); + string absolute = getAbsolute(p); + EnumeratorList enumerators = p->getEnumerators(); + + open(absolute, p->file()); + + Output& out = output(); + + out << sp; + + writeDocComment(out, p, getDeprecateReason(p, 0, "type")); + + out << nl << "public enum " << name; + if(!p->isLocal()) + { + out << " implements java.io.Serializable"; + } + out << sb; + + for(EnumeratorList::const_iterator en = enumerators.begin(); en != enumerators.end(); ++en) + { + if(en != enumerators.begin()) + { + out << ','; + } + out << nl; + writeDocComment(out, *en, getDeprecateReason(*en, 0, "enumerator")); + out << nl << fixKwd((*en)->name()) << '(' << (*en)->value() << ')'; + } + out << ';'; + + out << sp << nl << "public int" + << nl << "value()"; + out << sb; + out << nl << "return __value;"; + out << eb; + + out << sp << nl << "public static " << name + << nl << "valueOf(int __v)"; + out << sb; + out << nl << "switch(__v)"; + out << sb; + out.dec(); + for(EnumeratorList::const_iterator en = enumerators.begin(); en != enumerators.end(); ++en) + { + out << nl << "case " << (*en)->value() << ':'; + out.inc(); + out << nl << "return " << fixKwd((*en)->name()) << ';'; + out.dec(); + } + out.inc(); + out << eb; + out << nl << "return null;"; + out << eb; + + out << sp << nl << "private" + << nl << name << "(int __v)"; + out << sb; + out << nl << "__value = __v;"; + out << eb; + + if(!p->isLocal()) + { + out << sp << nl << "public void" << nl << "__write(Ice.OutputStream __os)"; + out << sb; + out << nl << "__os.writeEnum(value(), " << p->maxValue() << ");"; + out << eb; + + out << sp << nl << "public static void" << nl << "write(Ice.OutputStream __os, " << name << " __v)"; + out << sb; + out << nl << "if(__v == null)"; + out << sb; + string firstEnum = fixKwd(enumerators.front()->name()); + out << nl << "__os.writeEnum(" << absolute << '.' << firstEnum << ".value(), " << p->maxValue() << ");"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "__os.writeEnum(__v.value(), " << p->maxValue() << ");"; + out << eb; + out << eb; + + out << sp << nl << "public static " << name << nl << "read(Ice.InputStream __is)"; + out << sb; + out << nl << "int __v = __is.readEnum(" << p->maxValue() << ");"; + out << nl << "return __validate(__v);"; + out << eb; + + out << sp << nl << "private static " << name + << nl << "__validate(int __v)"; + out << sb; + out << nl << "final " << name << " __e = valueOf(__v);"; + out << nl << "if(__e == null)"; + out << sb; + out << nl << "throw new Ice.MarshalException(\"enumerator value \" + __v + \" is out of range\");"; + out << eb; + out << nl << "return __e;"; + out << eb; + } + + out << sp << nl << "private final int __value;"; + + out << eb; + close(); +} + +void +Slice::GenCompat::TypesVisitor::visitConst(const ConstPtr& p) +{ + string name = fixKwd(p->name()); + string package = getPackage(p); + string absolute = getAbsolute(p); + TypePtr type = p->type(); + + open(absolute, p->file()); + + Output& out = output(); + + out << sp; + writeDocComment(out, p, getDeprecateReason(p, 0, "constant")); + out << nl << "public interface " << name; + out << sb; + out << nl << typeToString(type, TypeModeIn, package) << " value = "; + writeConstantValue(out, type, p->valueType(), p->value(), package); + out << ';' << eb; + close(); +} + +bool +Slice::GenCompat::TypesVisitor::validateMethod(const OperationList& ops, const std::string& name, int numArgs, + const string& file, const string& line) +{ + for(OperationList::const_iterator i = ops.begin(); i != ops.end(); ++i) + { + if((*i)->name() == name) + { + int numParams = static_cast<int>((*i)->parameters().size()); + if(numArgs >= numParams && numArgs - numParams <= 1) + { + ostringstream ostr; + ostr << "operation `" << name << "' conflicts with method for data member"; + emitError(file, line, ostr.str()); + return false; + } + break; + } + } + return true; +} + +Slice::GenCompat::CompactIdVisitor::CompactIdVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::CompactIdVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string prefix = getPackagePrefix(p); + if(!prefix.empty()) + { + prefix = prefix + "."; + } + if(p->compactId() >= 0) + { + ostringstream os; + os << prefix << "IceCompactId.TypeId_" << p->compactId(); + open(os.str(), p->file()); + + Output& out = output(); + out << sp << nl << "public class TypeId_" << p->compactId(); + out << sb; + out << nl << "public final static String typeId = \"" << p->scoped() << "\";"; + out << eb; + + close(); + } + return false; +} + +Slice::GenCompat::HolderVisitor::HolderVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::HolderVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + ClassDeclPtr decl = p->declaration(); + writeHolder(decl); + + if(!p->isLocal()) + { + string name = p->name(); + string absolute = getAbsolute(p, "", "", "PrxHolder"); + + open(absolute, p->file()); + Output& out = output(); + + out << sp << nl << "public final class " << name << "PrxHolder"; + out << sb; + out << sp << nl << "public" << nl << name << "PrxHolder()"; + out << sb; + out << eb; + out << sp << nl << "public" << nl << name << "PrxHolder(" << name << "Prx value)"; + out << sb; + out << nl << "this.value = value;"; + out << eb; + out << sp << nl << "public " << name << "Prx value;"; + out << eb; + close(); + } + + return false; +} + +bool +Slice::GenCompat::HolderVisitor::visitStructStart(const StructPtr& p) +{ + writeHolder(p); + return false; +} + +void +Slice::GenCompat::HolderVisitor::visitSequence(const SequencePtr& p) +{ + if(sequenceHasHolder(p)) + { + writeHolder(p); + } +} + +void +Slice::GenCompat::HolderVisitor::visitDictionary(const DictionaryPtr& p) +{ + writeHolder(p); +} + +void +Slice::GenCompat::HolderVisitor::visitEnum(const EnumPtr& p) +{ + writeHolder(p); +} + +void +Slice::GenCompat::HolderVisitor::writeHolder(const TypePtr& p) +{ + ContainedPtr contained = ContainedPtr::dynamicCast(p); + assert(contained); + string name = contained->name(); + string absolute = getAbsolute(contained, "", "", "Holder"); + + + string file; + if(p->definitionContext()) + { + file = p->definitionContext()->filename(); + } + + open(absolute, file); + Output& out = output(); + + string typeS = typeToString(p, TypeModeIn, getPackage(contained)); + out << sp << nl << "public final class " << name << "Holder"; + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(p); + if(!p->isLocal() && ((builtin && builtin->kind() == Builtin::KindObject) || cl)) + { + out << " extends Ice.ObjectHolderBase<" << typeS << ">"; + } + else { + out << " extends Ice.Holder<" << typeS << ">"; + } + out << sb; + if(!p->isLocal() && ((builtin && builtin->kind() == Builtin::KindObject) || cl)) + { + out << sp << nl << "public" << nl << name << "Holder()"; + out << sb; + out << eb; + out << sp << nl << "public" << nl << name << "Holder(" << typeS << " value)"; + out << sb; + out << nl << "this.value = value;"; + out << eb; + + out << sp << nl << "public void"; + out << nl << "valueReady(Ice.Object v)"; + out << sb; + out << nl << "if(v == null || v instanceof " << typeS << ")"; + out << sb; + out << nl << "value = (" << typeS << ")v;"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "IceInternal.Ex.throwUOE(type(), v);"; + out << eb; + out << eb; + out << sp << nl << "public String" << nl << "type()"; + out << sb; + if(cl) + { + if(cl->isInterface()) + { + out << nl << "return _" << cl->name() << "Disp.ice_staticId();"; + } + else + { + out << nl << "return " << typeS << ".ice_staticId();"; + } + } + else + { + out << nl << "return \"" << p->typeId() << "\";"; + } + out << eb; + } + else + { + out << sp << nl << "public" << nl << name << "Holder()"; + out << sb; + out << eb; + out << sp << nl << "public" << nl << name << "Holder(" << typeS << " value)"; + out << sb; + out << nl << "super(value);"; + out << eb; + } + out << eb; + close(); +} + +Slice::GenCompat::HelperVisitor::HelperVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal()) + { + return false; + } + + // + // Proxy helper + // + string name = p->name(); + string scoped = p->scoped(); + string package = getPackage(p); + string absolute = getAbsolute(p); + + open(getAbsolute(p, "", "", "PrxHelper"), p->file()); + Output& out = output(); + + // + // A proxy helper class serves two purposes: it implements the + // proxy interface, and provides static helper methods for use + // by applications (e.g., checkedCast, etc.) + // + out << sp; + writeDocComment(out, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class"), + "Provides type-specific helper functions."); + out << nl << "public final class " << name << "PrxHelper extends Ice.ObjectPrxHelperBase implements " << name + << "Prx"; + + out << sb; + + string contextParam = "java.util.Map<String, String> __ctx"; + string explicitContextParam = "boolean __explicitCtx"; + + OperationList ops = p->allOperations(); + for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = *r; + const ContainerPtr container = op->container(); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + + out << sp; + out << nl << "private static final String __" << op->name() << "_name = \"" << op->name() << "\";"; + + // + // Use the optional mapping by default. + // + writeOperation(p, package, op, true); + + // + // If the operation actually sends any optionals, we generated overloaded methods + // that use the required mapping. + // + if(op->sendsOptionals()) + { + writeOperation(p, package, op, false); + } + + // + // End method + // + vector<string> outParams = getInOutParams(op, package, OutParam, true, true); + int iter = 0; + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + const TypePtr ret = op->returnType(); + const string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, op->returnIsOptional()); + + out << sp; + out << nl << "public " << retS << " end_" << op->name() << spar << outParams << "Ice.AsyncResult __iresult" + << epar; + writeThrowsClause(package, throws); + out << sb; + if(op->returnsData()) + { + out << nl << "IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__iresult, this, __" + << op->name() << "_name);"; + out << nl << "try"; + out << sb; + + out << nl << "if(!__result.__wait())"; + out << sb; + out << nl << "try"; + out << sb; + out << nl << "__result.throwUserException();"; + out << eb; + // + // Arrange exceptions into most-derived to least-derived order. If we don't + // do this, a base exception handler can appear before a derived exception + // handler, causing compiler warnings and resulting in the base exception + // being marshaled instead of the derived exception. + // +#if defined(__SUNPRO_CC) + throws.sort(Slice::derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + for(ExceptionList::const_iterator eli = throws.begin(); eli != throws.end(); ++eli) + { + out << nl << "catch(" << getAbsolute(*eli, package) << " __ex)"; + out << sb; + out << nl << "throw __ex;"; + out << eb; + } + out << nl << "catch(Ice.UserException __ex)"; + out << sb; + out << nl << "throw new Ice.UnknownUserException(__ex.ice_id(), __ex);"; + out << eb; + out << eb; + + if(ret || !outParams.empty()) + { + out << nl << "Ice.InputStream __is = __result.startReadParams();"; + const ParamDeclList paramList = op->parameters(); + ParamDeclList pl; + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + pl.push_back(*pli); + } + } + writeMarshalUnmarshalParams(out, package, pl, op, iter, false, true); + if(op->returnsClasses(false)) + { + out << nl << "__is.readPendingValues();"; + } + out << nl << "__result.endReadParams();"; + } + else + { + out << nl << "__result.readEmptyParams();"; + } + + if(ret) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(ret); + if(!op->returnIsOptional() && + ((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(ret))) + { + out << nl << "return __ret.value;"; + } + else + { + out << nl << "return __ret;"; + } + } + + out << eb; + out << nl << "finally"; + out << sb; + out << nl << "if(__result != null)"; + out << sb; + out << nl << "__result.cacheMessageBuffers();"; + out << eb; + out << eb; + } + else + { + out << nl << "__end(__iresult, __" << op->name() << "_name);"; + } + out << eb; + + // + // The async callbacks implementation of __completed method delegate to the static + // __<op-name>_completed method implemented bellow. + // + if(op->returnsData()) + { + const ParamDeclList paramList = op->parameters(); + ParamDeclList outParams; + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + outParams.push_back(*pli); + } + } + + out << sp << nl << "static public void __" << op->name() << "_completed(" + << getAsyncCallbackInterface(op, package) << " __cb, Ice.AsyncResult __result)"; + out << sb; + out << nl << getAbsolute(cl, "", "", "Prx") << " __proxy = (" + << getAbsolute(cl, "", "", "Prx") << ")__result.getProxy();"; + + TypePtr ret = op->returnType(); + if(ret) + { + out << nl << typeToString(ret, TypeModeIn, package, op->getMetaData(), true, + op->returnIsOptional()) + << " __ret = " << (op->returnIsOptional() ? "null" : initValue(ret)) << ';'; + } + for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) + { + string ts = typeToString((*pli)->type(), TypeModeOut, package, (*pli)->getMetaData(), true, + (*pli)->optional()); + out << nl << ts << ' ' << fixKwd((*pli)->name()) << " = new " << ts << "();"; + } + out << nl << "try"; + out << sb; + out << nl; + if(op->returnType()) + { + out << "__ret = "; + } + out << "__proxy.end_" << op->name() << spar << getInOutArgs(op, OutParam) << "__result" << epar + << ';'; + + out << eb; + if(!throws.empty()) + { + out << nl << "catch(Ice.UserException __ex)"; + out << sb; + out << nl << "__cb.exception(__ex);"; + out << nl << "return;"; + out << eb; + } + out << nl << "catch(Ice.LocalException __ex)"; + out << sb; + out << nl << "__cb.exception(__ex);"; + out << nl << "return;"; + out << eb; + out << nl << "catch(Ice.SystemException __ex)"; + out << sb; + out << nl << "__cb.exception(__ex);"; + out << nl << "return;"; + out << eb; + + out << nl << "__cb.response" << spar; + if(op->returnType()) + { + out << "__ret"; + } + for(ParamDeclList::const_iterator pli = outParams.begin(); pli != outParams.end(); ++pli) + { + if((*pli)->optional()) + { + out << fixKwd((*pli)->name()); + } + else + { + out << fixKwd((*pli)->name()) + ".value"; + } + } + out << epar << ';'; + + out << eb; + } + } + + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj)"; + out << sb; + out << nl << "return checkedCastImpl(__obj, ice_staticId(), " << name << "Prx.class, " + << name << "PrxHelper.class);"; + out << eb; + + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@param __ctx The Context map to send with the invocation.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj, " << contextParam << ')'; + out << sb; + out << nl << "return checkedCastImpl(__obj, __ctx, ice_staticId(), " << name + << "Prx.class, " << name << "PrxHelper.class);"; + out << eb; + + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that a facet of the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@param __facet The name of the desired facet.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj, String __facet)"; + out << sb; + out << nl << "return checkedCastImpl(__obj, __facet, ice_staticId(), " << name + << "Prx.class, " << name << "PrxHelper.class);"; + out << eb; + + out << sp; + writeDocComment(out, "", + "Contacts the remote server to verify that a facet of the object implements this type.\n" + "Raises a local exception if a communication error occurs.\n" + "@param __obj The untyped proxy.\n" + "@param __facet The name of the desired facet.\n" + "@param __ctx The Context map to send with the invocation.\n" + "@return A proxy for this type, or null if the object does not support this type."); + out << nl << "public static " << name << "Prx checkedCast(Ice.ObjectPrx __obj, String __facet, " + << contextParam << ')'; + out << sb; + out << nl << "return checkedCastImpl(__obj, __facet, __ctx, ice_staticId(), " << name + << "Prx.class, " << name << "PrxHelper.class);"; + out << eb; + + out << sp; + writeDocComment(out, "", + "Downcasts the given proxy to this type without contacting the remote server.\n" + "@param __obj The untyped proxy.\n" + "@return A proxy for this type."); + out << nl << "public static " << name << "Prx uncheckedCast(Ice.ObjectPrx __obj)"; + out << sb; + out << nl << "return uncheckedCastImpl(__obj, " << name << "Prx.class, " << name + << "PrxHelper.class);"; + out << eb; + + out << sp; + writeDocComment(out, "", + "Downcasts the given proxy to this type without contacting the remote server.\n" + "@param __obj The untyped proxy.\n" + "@param __facet The name of the desired facet.\n" + "@return A proxy for this type."); + out << nl << "public static " << name << "Prx uncheckedCast(Ice.ObjectPrx __obj, String __facet)"; + out << sb; + out << nl << "return uncheckedCastImpl(__obj, __facet, " << name << "Prx.class, " << name + << "PrxHelper.class);"; + out << eb; + + ClassList allBases = p->allBases(); + StringList ids; + transform(allBases.begin(), allBases.end(), back_inserter(ids), constMemFun(&Contained::scoped)); + StringList other; + other.push_back(scoped); + other.push_back("::Ice::Object"); + other.sort(); + ids.merge(other); + ids.unique(); + StringList::const_iterator firstIter = ids.begin(); + StringList::const_iterator scopedIter = find(ids.begin(), ids.end(), scoped); + assert(scopedIter != ids.end()); + StringList::difference_type scopedPos = ::IceUtilInternal::distance(firstIter, scopedIter); + + out << sp << nl << "public static final String[] __ids ="; + out << sb; + + for(StringList::const_iterator q = ids.begin(); q != ids.end();) + { + out << nl << '"' << *q << '"'; + if(++q != ids.end()) + { + out << ','; + } + } + + out << eb << ';'; + + out << sp; + writeDocComment(out, "", + "Provides the Slice type ID of this type.\n" + "@return The Slice type ID."); + out << nl << "public static String ice_staticId()"; + out << sb; + out << nl << "return __ids[" << scopedPos << "];"; + out << eb; + + out << sp << nl << "public static void write(Ice.OutputStream __os, " << name << "Prx v)"; + out << sb; + out << nl << "__os.writeProxy(v);"; + out << eb; + + out << sp << nl << "public static " << name << "Prx read(Ice.InputStream __is)"; + out << sb; + out << nl << "Ice.ObjectPrx proxy = __is.readProxy();"; + out << nl << "if(proxy != null)"; + out << sb; + out << nl << name << "PrxHelper result = new " << name << "PrxHelper();"; + out << nl << "result.__copyFrom(proxy);"; + out << nl << "return result;"; + out << eb; + out << nl << "return null;"; + out << eb; + + // + // Avoid serialVersionUID warnings for Proxy Helper classes. + // + out << sp << nl << "public static final long serialVersionUID = 0L;"; + out << eb; + + close(); + + return false; +} + +void +Slice::GenCompat::HelperVisitor::visitSequence(const SequencePtr& p) +{ + // + // Don't generate helper for a sequence of a local type. + // + if(p->isLocal()) + { + return; + } + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string prefix = "java:buffer"; + string meta; + if(p->findMetaData(prefix, meta)) + { + return; // No holders for buffer types. + } + } + + string name = p->name(); + string absolute = getAbsolute(p); + string helper = getAbsolute(p, "", "", "Helper"); + string package = getPackage(p); + string typeS = typeToString(p, TypeModeIn, package); + + // + // We cannot allocate an array of a generic type, such as + // + // arr = new Map<String, String>[sz]; + // + // Attempting to compile this code results in a "generic array creation" error + // message. This problem can occur when the sequence's element type is a + // dictionary, or when the element type is a nested sequence that uses a custom + // mapping. + // + // The solution is to rewrite the code as follows: + // + // arr = (Map<String, String>[])new Map[sz]; + // + // Unfortunately, this produces an unchecked warning during compilation, so we + // annotate the read() method to suppress the warning. + // + // A simple test is to look for a "<" character in the content type, which + // indicates the use of a generic type. + // + bool suppressUnchecked = false; + + string instanceType, formalType; + bool customType = getSequenceTypes(p, "", StringList(), instanceType, formalType); + + if(!customType) + { + // + // Determine sequence depth. + // + int depth = 0; + TypePtr origContent = p->type(); + SequencePtr s = SequencePtr::dynamicCast(origContent); + while(s) + { + // + // Stop if the inner sequence type has a custom, serializable or protobuf type. + // + if(hasTypeMetaData(s)) + { + break; + } + depth++; + origContent = s->type(); + s = SequencePtr::dynamicCast(origContent); + } + + string origContentS = typeToString(origContent, TypeModeIn, package); + suppressUnchecked = origContentS.find('<') != string::npos; + } + + open(helper, p->file()); + Output& out = output(); + + int iter; + + out << sp << nl << "public final class " << name << "Helper"; + out << sb; + + out << nl << "public static void" << nl << "write(Ice.OutputStream __os, " << typeS << " __v)"; + out << sb; + iter = 0; + writeSequenceMarshalUnmarshalCode(out, package, p, "__v", true, iter, false); + out << eb; + + out << sp; + if(suppressUnchecked) + { + out << nl << "@SuppressWarnings(\"unchecked\")"; + } + out << nl << "public static " << typeS << nl << "read(Ice.InputStream __is)"; + out << sb; + out << nl << typeS << " __v;"; + iter = 0; + writeSequenceMarshalUnmarshalCode(out, package, p, "__v", false, iter, false); + out << nl << "return __v;"; + out << eb; + + out << eb; + close(); +} + +void +Slice::GenCompat::HelperVisitor::visitDictionary(const DictionaryPtr& p) +{ + // + // Don't generate helper for a dictionary containing a local type + // + if(p->isLocal()) + { + return; + } + + TypePtr key = p->keyType(); + TypePtr value = p->valueType(); + + string name = p->name(); + string absolute = getAbsolute(p); + string helper = getAbsolute(p, "", "", "Helper"); + string package = getPackage(p); + StringList metaData = p->getMetaData(); + string formalType = typeToString(p, TypeModeIn, package, StringList(), true); + + open(helper, p->file()); + Output& out = output(); + + int iter; + + out << sp << nl << "public final class " << name << "Helper"; + out << sb; + + out << nl << "public static void" << nl << "write(Ice.OutputStream __os, " << formalType << " __v)"; + out << sb; + iter = 0; + writeDictionaryMarshalUnmarshalCode(out, package, p, "__v", true, iter, false); + out << eb; + + out << sp << nl << "public static " << formalType + << nl << "read(Ice.InputStream __is)"; + out << sb; + out << nl << formalType << " __v;"; + iter = 0; + writeDictionaryMarshalUnmarshalCode(out, package, p, "__v", false, iter, false); + out << nl << "return __v;"; + out << eb; + + out << eb; + close(); +} + +void +Slice::GenCompat::HelperVisitor::writeOperation(const ClassDefPtr& p, const string& package, const OperationPtr& op, + bool optionalMapping) +{ + const string name = p->name(); + Output& out = output(); + + const string contextParam = "java.util.Map<String, String> __ctx"; + const string explicitContextParam = "boolean __explicitCtx"; + + const ContainerPtr container = op->container(); + const ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + const string opName = fixKwd(op->name()); + const TypePtr ret = op->returnType(); + const string retS = typeToString(ret, TypeModeReturn, package, op->getMetaData(), true, op->returnIsOptional()); + + vector<string> params = getParamsProxy(op, package, false, optionalMapping); + vector<string> args = getArgs(op); + + ParamDeclList inParams; + ParamDeclList outParams; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + outParams.push_back(*pli); + } + else + { + inParams.push_back(*pli); + } + } + + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + + // + // Write two synchronous versions of the operation - with and without a + // context parameter. + // + out << sp << nl << "public " << retS << ' ' << opName << spar << params << epar; + writeThrowsClause(package, throws); + out << sb; + out << nl; + if(ret) + { + out << "return "; + } + out << opName << spar << args << "null" << "false" << epar << ';'; + out << eb; + + out << sp << nl << "public " << retS << ' ' << opName << spar << params << contextParam << epar; + writeThrowsClause(package, throws); + out << sb; + out << nl; + if(ret) + { + out << "return "; + } + out << opName << spar << args << "__ctx" << "true" << epar << ';'; + out << eb; + + out << sp; + out << nl << "private " << retS << ' ' << opName << spar << params << contextParam + << explicitContextParam << epar; + writeThrowsClause(package, throws); + out << sb; + + // This code replaces the synchronous calls with chained AMI calls. + if(op->returnsData()) + { + out << nl << "__checkTwowayOnly(__" << op->name() << "_name);"; + } + + if(ret) + { + out << nl << "return "; + } + else + { + out << nl; + } + + out << "end_" << op->name() << "("; + vector<string> inOutArgs = getInOutArgs(op, OutParam); + if(!inOutArgs.empty()) { + for(vector<string>::const_iterator p = inOutArgs.begin(); p != inOutArgs.end(); ++p) { + out << *p << ", "; + } + } + vector<string> inArgs = getInOutArgs(op, InParam); + out << "begin_" << op->name() << "("; + if(!inArgs.empty()) + { + for(vector<string>::const_iterator p = inArgs.begin(); p != inArgs.end(); ++p) { + out << *p << ", "; + } + } + out << "__ctx, __explicitCtx, true, null));"; + out << eb; + + { + // + // Write the asynchronous begin methods. + // + vector<string> inParams = getInOutParams(op, package, InParam, true, optionalMapping); + vector<string> inArgs = getInOutArgs(op, InParam); + const string callbackParam = "Ice.Callback __cb"; + const ParamDeclList paramList = op->parameters(); + int iter; + + // + // Type-unsafe begin methods + // + out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << epar; + out << sb; + out << nl << "return begin_" << op->name() << spar << inArgs << "null" << "false" << "false" << "null" << epar + << ';'; + out << eb; + + out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << contextParam << epar; + out << sb; + out << nl << "return begin_" << op->name() << spar << inArgs << "__ctx" << "true" << "false" << "null" << epar + << ';'; + out << eb; + + out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << callbackParam << epar; + out << sb; + out << nl << "return begin_" << op->name() << spar << inArgs << "null" << "false" << "false" << "__cb" << epar + << ';'; + out << eb; + + out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << contextParam + << callbackParam << epar; + out << sb; + out << nl << "return begin_" << op->name() << spar << inArgs << "__ctx" << "true" << "false" << "__cb" << epar + << ';'; + out << eb; + + // + // Type-safe begin methods + // + string typeSafeCallbackParam; + + // + // Get the name of the callback using the name of the class in which this + // operation was defined. + // + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string opClassName = getAbsolute(cl, package, "Callback_", '_' + op->name()); + typeSafeCallbackParam = opClassName + " __cb"; + + out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << typeSafeCallbackParam + << epar; + out << sb; + out << nl << "return begin_" << op->name() << spar << inArgs << "null" << "false" << "false" << "__cb" << epar + << ';'; + out << eb; + + out << sp << nl << "public Ice.AsyncResult begin_" << op->name() << spar << inParams << contextParam + << typeSafeCallbackParam << epar; + out << sb; + out << nl << "return begin_" << op->name() << spar << inArgs << "__ctx" << "true" << "false" << "__cb" << epar + << ';'; + out << eb; + + // + // Async methods that accept Java 8 lambda callbacks. + // + out << sp; + out << nl << "public Ice.AsyncResult begin_" << op->name(); + writeParamList(out, getParamsAsyncLambda(op, package, false, false, optionalMapping)); + out << sb; + out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package) << epar << ';'; + out << eb; + + out << sp; + out << nl << "public Ice.AsyncResult begin_" << op->name(); + writeParamList(out, getParamsAsyncLambda(op, package, false, true, optionalMapping)); + out << sb; + out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package, false, true) << epar + << ';'; + out << eb; + + out << sp; + out << nl << "public Ice.AsyncResult begin_" << op->name(); + writeParamList(out, getParamsAsyncLambda(op, package, true, false, optionalMapping)); + out << sb; + out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package, true) << epar << ';'; + out << eb; + + out << sp; + out << nl << "public Ice.AsyncResult begin_" << op->name(); + writeParamList(out, getParamsAsyncLambda(op, package, true, true, optionalMapping)); + out << sb; + out << nl << "return begin_" << op->name() << spar << getArgsAsyncLambda(op, package, true, true) << epar + << ';'; + out << eb; + + vector<string> params = inParams; + params.push_back(contextParam); + params.push_back("boolean __explicitCtx"); + params.push_back("boolean __synchronous"); + vector<string> asyncParams = getParamsAsyncLambda(op, package, false, true, optionalMapping, false); + copy(asyncParams.begin(), asyncParams.end(), back_inserter(params)); + + out << sp; + out << nl << "private Ice.AsyncResult begin_" << op->name(); + writeParamList(out, params); + out << sb; + + ParamDeclList outParams = getOutParams(op); + + if(!op->returnsData()) + { + params = getInOutArgs(op, InParam); + params.push_back("__ctx"); + params.push_back("__explicitCtx"); + params.push_back("__synchronous"); + params.push_back("new IceInternal.Functional_OnewayCallback(__responseCb, __exceptionCb, __sentCb)"); + out << nl << "return begin_" << op->name(); + writeParamList(out, params); + out << ';'; + } + else if((ret && !outParams.empty()) || (outParams.size() > 1)) + { + params.clear(); + params.push_back(getLambdaResponseCB(op, package) + " responseCb"); + if(!throws.empty()) + { + params.push_back("IceInternal.Functional_GenericCallback1<Ice.UserException> userExceptionCb"); + } + params.push_back("IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb"); + params.push_back("IceInternal.Functional_BoolCallback sentCb"); + + out << sp; + out << nl << "class CB extends " << getAsyncCallbackBaseClass(op, true); + out << sb; + out << nl << "public CB"; + writeParamList(out, params); + out << sb; + out << nl << "super(responseCb != null, "; + if(!throws.empty()) + { + out << "userExceptionCb, "; + } + out << "exceptionCb, sentCb);"; + out << nl << "__responseCb = responseCb;"; + out << eb; + + out << sp; + out << nl << "public void response" << spar << getParamsAsyncCB(op, package, false, true) << epar; + out << sb; + out << nl << "if(__responseCb != null)"; + out << sb; + out << nl << "__responseCb.apply" << spar; + if(ret) + { + out << "__ret"; + } + out << getInOutArgs(op, OutParam) << epar << ';'; + out << eb; + out << eb; + + out << sp; + out << nl << "public final void __completed(Ice.AsyncResult __result)"; + out << sb; + out << nl << p->name() << "PrxHelper.__" << op->name() << "_completed(this, __result);"; + out << eb; + out << sp; + out << nl << "private final " << getLambdaResponseCB(op, package) << " __responseCb;"; + out << eb; + + out << nl << "return begin_" << op->name() << spar << getInOutArgs(op, InParam) << "__ctx" + << "__explicitCtx" + << "__synchronous" + << (throws.empty() ? "new CB(__responseCb, __exceptionCb, __sentCb)" : + "new CB(__responseCb, __userExceptionCb, __exceptionCb, __sentCb)") + << epar << ';'; + } + else + { + params = getInOutArgs(op, InParam); + params.push_back("__ctx"); + params.push_back("__explicitCtx"); + params.push_back("__synchronous"); + + const string baseClass = getAsyncCallbackBaseClass(op, true); + out << nl << "return begin_" << op->name(); + writeParamList(out, params, false, false); + out << nl + << (throws.empty() ? "new " + baseClass + "(__responseCb, __exceptionCb, __sentCb)" : + "new " + baseClass + "(__responseCb, __userExceptionCb, __exceptionCb, __sentCb)"); + out.inc(); + out << sb; + out << nl << "public final void __completed(Ice.AsyncResult __result)"; + out << sb; + out << nl << p->name() << "PrxHelper.__" << op->name() << "_completed(this, __result);"; + out << eb; + out << eb; + out << ");"; + out.dec(); + out.restoreIndent(); + } + out << eb; + + // + // Implementation of begin method + // + params = inParams; + params.push_back(contextParam); + params.push_back("boolean __explicitCtx"); + params.push_back("boolean __synchronous"); + params.push_back("IceInternal.CallbackBase __cb"); + + out << sp; + out << nl << "private Ice.AsyncResult begin_" << op->name(); + writeParamList(out, params); + out << sb; + if(op->returnsData()) + { + out << nl << "__checkAsyncTwowayOnly(__" << op->name() << "_name);"; + } + out << nl << "IceInternal.OutgoingAsync __result = getOutgoingAsync(__" << op->name() + << "_name, __cb);"; + out << nl << "try"; + out << sb; + + out << nl << "__result.prepare(__" << op->name() << "_name, " << sliceModeToIceMode(op->sendMode()) + << ", __ctx, __explicitCtx, __synchronous);"; + + iter = 0; + if(!inArgs.empty()) + { + out << nl << "Ice.OutputStream __os = __result.startWriteParams(" + << opFormatTypeToString(op) << ");"; + ParamDeclList pl; + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if(!(*pli)->isOutParam()) + { + pl.push_back(*pli); + } + } + writeMarshalUnmarshalParams(out, package, pl, 0, iter, true, optionalMapping); + if(op->sendsClasses(false)) + { + out << nl << "__os.writePendingValues();"; + } + out << nl << "__result.endWriteParams();"; + } + else + { + out << nl << "__result.writeEmptyParams();"; + } + + out << nl << "__result.invoke();"; + out << eb; + out << nl << "catch(Ice.Exception __ex)"; + out << sb; + out << nl << "__result.abort(__ex);"; + out << eb; + out << nl << "return __result;"; + out << eb; + } +} + +Slice::GenCompat::ProxyVisitor::ProxyVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::ProxyVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal()) + { + return false; + } + + string name = p->name(); + ClassList bases = p->bases(); + string package = getPackage(p); + string absolute = getAbsolute(p, "", "", "Prx"); + + open(absolute, p->file()); + + Output& out = output(); + + // + // Generate a Java interface as the user-visible type + // + out << sp; + writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); + out << nl << "public interface " << name << "Prx extends "; + if(bases.empty()) + { + out << "Ice.ObjectPrx"; + } + else + { + out.useCurrentPosAsIndent(); + for(ClassList::const_iterator q = bases.begin(); q != bases.end();) + { + out << getAbsolute(*q, package, "", "Prx"); + if(++q != bases.end()) + { + out << ',' << nl; + } + } + out.restoreIndent(); + } + + out << sb; + + return true; +} + +void +Slice::GenCompat::ProxyVisitor::visitClassDefEnd(const ClassDefPtr&) +{ + Output& out = output(); + out << eb; + close(); +} + +void +Slice::GenCompat::ProxyVisitor::visitOperation(const OperationPtr& p) +{ + string name = fixKwd(p->name()); + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string package = getPackage(cl); + + Output& out = output(); + + TypePtr ret = p->returnType(); + string retS = typeToString(ret, TypeModeReturn, package, p->getMetaData(), true, p->returnIsOptional()); + vector<string> params = getParamsProxy(p, package, false, true); + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); + + string deprecateReason = getDeprecateReason(p, cl, "operation"); + string contextDoc = "@param __ctx The Context map to send with the invocation."; + string contextParam = "java.util.Map<String, String> __ctx"; + string lambdaResponseDoc = "@param __responseCb The lambda response callback."; + string lambdaUserExDoc = "@param __userExceptionCb The lambda user exception callback."; + string lambdaExDoc = "@param __exceptionCb The lambda exception callback."; + string lambdaSentDoc = "@param __sentCb The lambda sent callback."; + + const bool optional = p->sendsOptionals(); + + // + // Write two synchronous versions of the operation - with and without a context parameter. + // + out << sp; + writeDocComment(out, p, deprecateReason); + + out << nl << "public " << retS << ' ' << name << spar << params << epar; + writeThrowsClause(package, throws); + out << ';'; + + out << sp; + writeDocComment(out, p, deprecateReason, contextDoc); + + out << nl << "public " << retS << ' ' << name << spar << params << contextParam << epar; + writeThrowsClause(package, throws); + out << ';'; + + if(optional) + { + // + // Write overloaded versions of the methods using required params. + // + vector<string> reqParams = getParamsProxy(p, package, false, false); + + out << sp; + writeDocComment(out, p, deprecateReason); + out << nl << "public " << retS << ' ' << name << spar << reqParams << epar; + writeThrowsClause(package, throws); + out << ';'; + + out << sp; + writeDocComment(out, p, deprecateReason, contextDoc); + out << nl << "public " << retS << ' ' << name << spar << reqParams << contextParam << epar; + writeThrowsClause(package, throws); + out << ';'; + } + + { + // + // Write the asynchronous begin/end methods. + // + // Start with the type-unsafe begin methods. + // + vector<string> inParams = getInOutParams(p, package, InParam, true, true); + string callbackParam = "Ice.Callback __cb"; + string callbackDoc = "@param __cb The asynchronous callback object."; + + out << sp; + writeDocCommentAMI(out, p, InParam); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << callbackParam << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << callbackParam + << epar << ';'; + + // + // Type-safe begin methods. + // + string typeSafeCallbackParam; + + // + // Get the name of the callback using the name of the class in which this + // operation was defined. + // + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string opClassName = getAbsolute(cl, package, "Callback_", '_' + p->name()); + typeSafeCallbackParam = opClassName + " __cb"; + + out << sp; + writeDocCommentAMI(out, p, InParam, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << typeSafeCallbackParam + << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam + << typeSafeCallbackParam << epar << ';'; + + // + // Generate the Callback Response interface if the operation has more than one + // return parameter. Operations with just one return parameter use one of the + // builtin async callback interfaces. + // + { + ParamDeclList outParams = getOutParams(p); + if((ret && !outParams.empty()) || outParams.size() > 1) + { + vector<string> params = getParamsAsyncCB(p, package, false, true); + out << sp; + out << nl << "public interface " << getLambdaResponseCB(p, package); + out << sb; + out << nl << "void apply" << spar << params << epar << ';'; + out << eb; + } + } + + // + // Async methods that accept Java 8 lambda callbacks. + // + { + out << sp; + writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package, false, false, true)); + out << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc, + lambdaSentDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package, false, true, true)); + out << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, + lambdaExDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package, true, false, true)); + out << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, + lambdaExDoc, lambdaSentDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package, true, true, true)); + out << ';'; + } + + vector<string> outParams = getInOutParams(p, package, OutParam, true, true); + + out << sp; + writeDocCommentAMI(out, p, OutParam); + out << nl << "public " << retS << " end_" << p->name() << spar << outParams << "Ice.AsyncResult __result" + << epar; + writeThrowsClause(package, throws); + out << ';'; + } + + if(optional) + { + // + // Write overloaded versions of the methods using required params. + // + vector<string> inParams = getInOutParams(p, package, InParam, true, false); + string callbackParam = "Ice.Callback __cb"; + string callbackDoc = "@param __cb The asynchronous callback object."; + + out << sp; + writeDocCommentAMI(out, p, InParam); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << callbackParam << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam << callbackParam + << epar << ';'; + + // + // Async methods that accept Java 8 lambda callbacks. + // + { + out << sp; + writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package)); + out << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, lambdaExDoc, + lambdaSentDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package, false, true)); + out << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, + lambdaExDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package, true)); + out << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, lambdaResponseDoc, throws.empty() ? "" : lambdaUserExDoc, + lambdaExDoc, lambdaSentDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name(); + writeParamList(out, getParamsAsyncLambda(p, package, true, true)); + out << ';'; + } + + // + // Type-safe begin methods. + // + string typeSafeCallbackParam; + + // + // Get the name of the callback using the name of the class in which this + // operation was defined. + // + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string opClassName = getAbsolute(cl, package, "Callback_", '_' + p->name()); + typeSafeCallbackParam = opClassName + " __cb"; + + out << sp; + writeDocCommentAMI(out, p, InParam, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << typeSafeCallbackParam + << epar << ';'; + + out << sp; + writeDocCommentAMI(out, p, InParam, contextDoc, callbackDoc); + out << nl << "public Ice.AsyncResult begin_" << p->name() << spar << inParams << contextParam + << typeSafeCallbackParam << epar << ';'; + } +} + +Slice::GenCompat::DispatcherVisitor::DispatcherVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +bool +Slice::GenCompat::DispatcherVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal() || !p->isInterface()) + { + return false; + } + + string name = p->name(); + ClassList bases = p->bases(); + string absolute = getAbsolute(p, "", "_", "Disp"); + + open(absolute, p->file()); + + Output& out = output(); + + out << sp; + writeDocComment(out, p, getDeprecateReason(p, 0, p->isInterface() ? "interface" : "class")); + out << nl << "public abstract class _" << name << "Disp extends Ice.ObjectImpl implements " << fixKwd(name); + out << sb; + + out << sp << nl << "protected void" << nl << "ice_copyStateFrom(Ice.Object __obj)"; + out.inc(); + out << nl << "throws java.lang.CloneNotSupportedException"; + out.dec(); + out << sb; + out << nl << "throw new java.lang.CloneNotSupportedException();"; + out << eb; + + writeDispatchAndMarshalling(out, p); + + // + // Avoid serialVersionUID warnings for dispatch classes. + // + out << sp << nl << "public static final long serialVersionUID = 0L;"; + out << eb; + close(); + + return false; +} + +Slice::GenCompat::BaseImplVisitor::BaseImplVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +void +Slice::GenCompat::BaseImplVisitor::writeDecl(Output& out, const string& package, const string& name, const TypePtr& type, + const StringList& metaData, bool optional) +{ + string typeS = typeToString(type, TypeModeIn, package, metaData, true, optional); + out << nl << typeS << ' ' << name; + + if(optional) + { + out << " = new " << typeS << "();"; + } + else + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + out << " = false"; + break; + } + case Builtin::KindByte: + { + out << " = (byte)0"; + break; + } + case Builtin::KindShort: + { + out << " = (short)0"; + break; + } + case Builtin::KindInt: + case Builtin::KindLong: + { + out << " = 0"; + break; + } + case Builtin::KindFloat: + { + out << " = (float)0.0"; + break; + } + case Builtin::KindDouble: + { + out << " = 0.0"; + break; + } + case Builtin::KindString: + { + out << " = \"\""; + break; + } + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + out << " = null"; + break; + } + } + } + else + { + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + EnumeratorList enumerators = en->getEnumerators(); + out << " = " << getAbsolute(en, package) << '.' << fixKwd(enumerators.front()->name()); + } + else + { + out << " = null"; + } + } + + out << ';'; + } +} + +void +Slice::GenCompat::BaseImplVisitor::writeReturn(Output& out, const TypePtr& type, bool optional) +{ + if(optional) + { + out << nl << "return null;"; + } + else + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + out << nl << "return false;"; + break; + } + case Builtin::KindByte: + { + out << nl << "return (byte)0;"; + break; + } + case Builtin::KindShort: + { + out << nl << "return (short)0;"; + break; + } + case Builtin::KindInt: + case Builtin::KindLong: + { + out << nl << "return 0;"; + break; + } + case Builtin::KindFloat: + { + out << nl << "return (float)0.0;"; + break; + } + case Builtin::KindDouble: + { + out << nl << "return 0.0;"; + break; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + out << nl << "return null;"; + break; + } + } + return; + } + + out << nl << "return null;"; + } +} + +void +Slice::GenCompat::BaseImplVisitor::writeOperation(Output& out, const string& package, const OperationPtr& op, bool local) +{ + string opName = op->name(); + + const TypePtr ret = op->returnType(); + const bool optionalMapping = useOptionalMapping(op); + const StringList opMetaData = op->getMetaData(); + const string retS = typeToString(ret, TypeModeReturn, package, opMetaData, true, + optionalMapping && op->returnIsOptional()); + vector<string> params = getParams(op, package, false, optionalMapping); + + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + + if(!local && (cl->hasMetaData("amd") || op->hasMetaData("amd"))) + { + vector<string> paramsAMD = getParamsAsync(op, package, true, true); + + out << sp << nl << "public void " << opName << "_async" << spar << paramsAMD << "Ice.Current __current" + << epar; + + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + + // + // Arrange exceptions into most-derived to least-derived order. If we don't + // do this, a base exception handler can appear before a derived exception + // handler, causing compiler warnings and resulting in the base exception + // being marshaled instead of the derived exception. + // +#if defined(__SUNPRO_CC) + throws.sort(Slice::derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + writeThrowsClause(package, throws); + + out << sb; + + string result = "__r"; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->name() == result) + { + result = "_" + result; + break; + } + } + if(ret) + { + writeDecl(out, package, result, ret, opMetaData, optionalMapping && op->returnIsOptional()); + } + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + writeDecl(out, package, fixKwd((*q)->name()), (*q)->type(), (*q)->getMetaData(), + optionalMapping && (*q)->optional()); + } + } + + out << nl << "__cb.ice_response("; + if(ret) + { + out << result; + } + bool firstOutParam = true; + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + if(ret || !firstOutParam) + { + out << ", "; + } + out << fixKwd((*q)->name()); + firstOutParam = false; + } + } + out << ");"; + + out << eb; + } + else + { + out << sp << nl << "public " << retS << nl << fixKwd(opName) << spar << params; + if(!local) + { + out << "Ice.Current __current"; + } + out << epar; + + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + + if(op->hasMetaData("UserException")) + { + out.inc(); + out << nl << "throws Ice.UserException"; + out.dec(); + } + else + { + writeThrowsClause(package, throws); + } + + out << sb; + + // + // Return value + // + if(ret) + { + writeReturn(out, ret, optionalMapping && op->returnIsOptional()); + } + + out << eb; + } +} + +Slice::GenCompat::ImplVisitor::ImplVisitor(const string& dir) : + BaseImplVisitor(dir) +{ +} + +bool +Slice::GenCompat::ImplVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(!p->isAbstract()) + { + return false; + } + + string name = p->name(); + ClassList bases = p->bases(); + string package = getPackage(p); + string absolute = getAbsolute(p, "", "", "I"); + + open(absolute, p->file()); + + Output& out = output(); + + out << sp << nl << "public final class " << name << 'I'; + if(p->isInterface()) + { + if(p->isLocal()) + { + out << " implements " << fixKwd(name); + } + else + { + out << " extends _" << name << "Disp"; + } + } + else + { + out << " extends " << fixKwd(name); + } + out << sb; + + out << nl << "public" << nl << name << "I()"; + out << sb; + out << eb; + + OperationList ops = p->allOperations(); + for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + { + writeOperation(out, package, *r, p->isLocal()); + } + + out << eb; + close(); + + return false; +} + +Slice::GenCompat::ImplTieVisitor::ImplTieVisitor(const string& dir) : + BaseImplVisitor(dir) +{ +} + +bool +Slice::GenCompat::ImplTieVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(!p->isAbstract()) + { + return false; + } + + string name = p->name(); + ClassList bases = p->bases(); + string package = getPackage(p); + string absolute = getAbsolute(p, "", "", "I"); + + open(absolute, p->file()); + + Output& out = output(); + + // + // Use implementation inheritance in the following situations: + // + // * if a class extends another class + // * if a class implements a single interface + // * if an interface extends only one interface + // + bool inheritImpl = (!p->isInterface() && !bases.empty() && !bases.front()->isInterface()) || (bases.size() == 1); + + out << sp << nl << "public class " << name << 'I'; + if(inheritImpl) + { + out << " extends "; + if(bases.front()->isAbstract()) + { + out << bases.front()->name() << 'I'; + } + else + { + out << fixKwd(bases.front()->name()); + } + } + out << " implements " << '_' << name << "Operations"; + if(p->isLocal()) + { + out << "NC"; + } + out << sb; + + out << nl << "public" << nl << name << "I()"; + out << sb; + out << eb; + + OperationList ops = p->allOperations(); + ops.sort(); + + OperationList baseOps; + if(inheritImpl) + { + baseOps = bases.front()->allOperations(); + baseOps.sort(); + } + + for(OperationList::iterator r = ops.begin(); r != ops.end(); ++r) + { + if(inheritImpl && binary_search(baseOps.begin(), baseOps.end(), *r)) + { + out << sp; + out << nl << "/*"; + out << nl << " * Implemented by " << bases.front()->name() << 'I'; + out << nl << " *"; + writeOperation(out, package, *r, p->isLocal()); + out << sp; + out << nl << "*/"; + } + else + { + writeOperation(out, package, *r, p->isLocal()); + } + } + + out << eb; + close(); + + return false; +} + +Slice::GenCompat::AsyncVisitor::AsyncVisitor(const string& dir) : + JavaCompatVisitor(dir) +{ +} + +void +Slice::GenCompat::AsyncVisitor::visitOperation(const OperationPtr& p) +{ + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + + if(cl->isLocal()) + { + return; + } + + string name = p->name(); + string classPkg = getPackage(cl); + StringList opMetaData = p->getMetaData(); + + // + // Generate new-style callback. + // + { + TypePtr ret = p->returnType(); + ParamDeclList outParams; + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + outParams.push_back(*pli); + } + } + + vector<string> params = getParamsAsyncCB(p, classPkg, false, true); + vector<string> args = getInOutArgs(p, OutParam); + ExceptionList throws = p->throws(); + + // + // If the operation has more than one return parameter we generate a Callback + // interface to use in the method signatures. + // + if(p->returnsData() && ((ret && !outParams.empty()) || outParams.size() > 1)) + { + open(getAbsolute(cl, "", "_Callback_", "_" + name), p->file()); + + Output& out = output(); + + writeDocCommentOp(out, p); + out << sp << nl << "public interface " << ("_Callback_" + cl->name()) << '_' << name + << " extends " << (throws.empty() ? "Ice.TwowayCallback" : "Ice.TwowayCallbackUE"); + out << sb; + out << nl << "public void response" << spar << params << epar << ';'; + out << eb; + + close(); + } + + string classNameAsync = "Callback_" + cl->name(); + string absoluteAsync = getAbsolute(cl, "", "Callback_", "_" + name); + + open(absoluteAsync, p->file()); + + Output& out = output(); + + writeDocCommentOp(out, p); + out << sp << nl << "public abstract class " << classNameAsync << '_' << name; + + if(p->returnsData()) + { + out.inc(); + out << nl << "extends " << getAsyncCallbackBaseClass(p, false); + out.dec(); + out << sb; + + out << sp << nl << "public final void __completed(Ice.AsyncResult __result)"; + out << sb; + out << nl << cl->name() << "PrxHelper.__" << p->name() << "_completed(this, __result);"; + out << eb; + + out << eb; + } + else + { + out << " extends Ice.OnewayCallback"; + out << sb; + out << eb; + } + + close(); + } + + if(cl->hasMetaData("amd") || p->hasMetaData("amd")) + { + string classNameAMD = "AMD_" + cl->name(); + string absoluteAMD = getAbsolute(cl, "", "AMD_", "_" + name); + + string classNameAMDI = "_AMD_" + cl->name(); + string absoluteAMDI = getAbsolute(cl, "", "_AMD_", "_" + name); + + const bool optionalMapping = useOptionalMapping(p); + vector<string> paramsAMD = getParamsAsyncCB(p, classPkg, true, optionalMapping); + + { + open(absoluteAMD, p->file()); + + Output& out = output(); + + writeDocCommentOp(out, p); + out << sp << nl << "public interface " << classNameAMD << '_' << name; + out << " extends Ice.AMDCallback"; + out << sb; + out << sp; + writeDocCommentAsync(out, p, OutParam); + out << nl << "void ice_response" << spar << paramsAMD << epar << ';'; + + out << eb; + + close(); + } + + { + open(absoluteAMDI, p->file()); + + Output& out = output(); + + TypePtr ret = p->returnType(); + + ParamDeclList outParams; + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + outParams.push_back(*pli); + } + } + + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); + + // + // Arrange exceptions into most-derived to least-derived order. If we don't + // do this, a base exception handler can appear before a derived exception + // handler, causing compiler warnings and resulting in the base exception + // being marshaled instead of the derived exception. + // +#if defined(__SUNPRO_CC) + throws.sort(Slice::derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + + int iter; + + out << sp << nl << "final class " << classNameAMDI << '_' << name + << " extends IceInternal.IncomingAsync implements " << classNameAMD << '_' << name; + out << sb; + + out << sp << nl << "public " << classNameAMDI << '_' << name << "(IceInternal.Incoming in)"; + out << sb; + out << nl << "super(in);"; + out << eb; + + out << sp << nl << "public void ice_response" << spar << paramsAMD << epar; + out << sb; + iter = 0; + out << nl << "if(__validateResponse(true))"; + out << sb; + if(ret || !outParams.empty()) + { + out << nl << "try"; + out << sb; + out << nl << "Ice.OutputStream __os = this.__startWriteParams(" + << opFormatTypeToString(p) << ");"; + writeMarshalUnmarshalParams(out, classPkg, outParams, p, iter, true, optionalMapping, false); + if(p->returnsClasses(false)) + { + out << nl << "__os.writePendingValues();"; + } + out << nl << "this.__endWriteParams(true);"; + out << eb; + out << nl << "catch(Ice.LocalException __ex)"; + out << sb; + out << nl << "__exception(__ex);"; + out << nl << "return;"; + out << eb; + } + else + { + out << nl << "__writeEmptyParams();"; + } + out << nl << "__response();"; + out << eb; + out << eb; + + if(!throws.empty()) + { + out << sp << nl << "public void ice_exception(java.lang.Exception ex)"; + out << sb; + out << nl << "try"; + out << sb; + out << nl << "throw ex;"; + out << eb; + for(ExceptionList::const_iterator r = throws.begin(); r != throws.end(); ++r) + { + string exS = getAbsolute(*r, classPkg); + out << nl << "catch(" << exS << " __ex)"; + out << sb; + out << nl << "if(__validateResponse(false))"; + out << sb; + out << nl << "__writeUserException(__ex, " << opFormatTypeToString(p) << ");"; + out << nl << "__response();"; + out << eb; + out << eb; + } + out << nl << "catch(java.lang.Exception __ex)"; + out << sb; + out << nl << "super.ice_exception(__ex);"; + out << eb; + out << eb; + } + + out << eb; + + close(); + } + } +} diff --git a/cpp/src/slice2java/GenCompat.h b/cpp/src/slice2java/GenCompat.h new file mode 100644 index 00000000000..c03d491f380 --- /dev/null +++ b/cpp/src/slice2java/GenCompat.h @@ -0,0 +1,317 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef GEN_COMPAT_H +#define GEN_COMPAT_H + +#include <Slice/Parser.h> +#include <Slice/JavaUtil.h> +#include <Slice/Checksum.h> + +namespace Slice +{ + +class JavaCompatVisitor : public JavaCompatGenerator, public ParserVisitor +{ +public: + + virtual ~JavaCompatVisitor(); + +protected: + + JavaCompatVisitor(const std::string&); + + enum ParamDir { InParam, OutParam }; + + ParamDeclList getOutParams(const OperationPtr&); + + // + // Compose the parameter lists for an operation. + // + std::vector<std::string> getParams(const OperationPtr&, const std::string&, bool, bool); + std::vector<std::string> getParamsProxy(const OperationPtr&, const std::string&, bool, bool); + std::vector<std::string> getInOutParams(const OperationPtr&, const std::string&, ParamDir, bool, bool); + std::vector<std::string> getParamsAsync(const OperationPtr&, const std::string&, bool, bool); + std::vector<std::string> getParamsAsyncCB(const OperationPtr&, const std::string&, bool, bool); + + std::string getAsyncCallbackInterface(const OperationPtr&, const std::string&); + std::string getAsyncCallbackBaseClass(const OperationPtr&, bool); + std::string getLambdaResponseCB(const OperationPtr&, const std::string&); + std::vector<std::string> getParamsAsyncLambda(const OperationPtr&, const std::string&, + bool context = false, bool sentCB = false, + bool optionalMapping = false, + bool inParams = true); + std::vector<std::string> getArgsAsyncLambda(const OperationPtr&, const std::string&, + bool context = false, bool sentCB = false); + + // + // Compose the argument lists for an operation. + // + std::vector<std::string> getArgs(const OperationPtr&); + std::vector<std::string> getInOutArgs(const OperationPtr&, ParamDir); + std::vector<std::string> getArgsAsync(const OperationPtr&); + std::vector<std::string> getArgsAsyncCB(const OperationPtr&); + + void writeMarshalUnmarshalParams(::IceUtilInternal::Output&, const std::string&, const ParamDeclList&, + const OperationPtr&, int&, bool, bool, bool = false); + + // + // Generate a throws clause containing only non-local exceptions. + // + void writeThrowsClause(const std::string&, const ExceptionList&); + + // + // Generate code to compute a hash code for a type. + // + void writeHashCode(::IceUtilInternal::Output&, const TypePtr&, const std::string&, int&, + const std::list<std::string>& = std::list<std::string>()); + + // + // Marshal/unmarshal a data member. + // + void writeMarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&); + void writeUnmarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&, + bool, int&); + void writeStreamMarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&); + void writeStreamUnmarshalDataMember(::IceUtilInternal::Output&, const std::string&, const DataMemberPtr&, int&, + bool, int&); + + // + // Generate a patcher class. + // + void writePatcher(::IceUtilInternal::Output&, const std::string&, const DataMemberList&, const DataMemberList&); + + // + // Generate dispatch and marshalling methods for a class or interface. + // + void writeDispatchAndMarshalling(::IceUtilInternal::Output&, const ClassDefPtr&); + + // + // Write a constant or default value initializer. + // + void writeConstantValue(::IceUtilInternal::Output&, const TypePtr&, const SyntaxTreeBasePtr&, const std::string&, + const std::string&); + + // + // Generate assignment statements for those data members that have default values. + // + void writeDataMemberInitializers(::IceUtilInternal::Output&, const DataMemberList&, const std::string&); + + // + // Write doc comments. + // + static StringList splitComment(const ContainedPtr&); + static void writeDocComment(::IceUtilInternal::Output&, const ContainedPtr&, + const std::string&, const std::string& = ""); + static void writeDocComment(::IceUtilInternal::Output&, const std::string&, const std::string&); + static void writeDocCommentOp(::IceUtilInternal::Output&, const OperationPtr&); + + static void writeDocCommentAsync(::IceUtilInternal::Output&, const OperationPtr&, + ParamDir, const std::string& = ""); + static void writeDocCommentAMI(::IceUtilInternal::Output&, const OperationPtr&, ParamDir, const std::string& = "", + const std::string& = "", const std::string& = "", const std::string& = "", + const std::string& = ""); + static void writeDocCommentParam(::IceUtilInternal::Output&, const OperationPtr&, ParamDir, bool = true); +}; + +class GenCompat : private ::IceUtil::noncopyable +{ +public: + + GenCompat(const std::string&, + const std::string&, + const std::vector<std::string>&, + const std::string&); + ~GenCompat(); + + void generate(const UnitPtr&); + void generateTie(const UnitPtr&); + void generateImpl(const UnitPtr&); + void generateImplTie(const UnitPtr&); + + static void writeChecksumClass(const std::string&, const std::string&, const ChecksumMap&); + +private: + + std::string _base; + std::vector<std::string> _includePaths; + std::string _dir; + + class OpsVisitor : public JavaCompatVisitor + { + public: + + OpsVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + + private: + void writeOperations(const ClassDefPtr&, bool); + }; + + class TieVisitor : public JavaCompatVisitor + { + public: + + TieVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + }; + + class PackageVisitor : public JavaCompatVisitor + { + public: + + PackageVisitor(const std::string&); + + virtual bool visitModuleStart(const ModulePtr&); + }; + + class TypesVisitor : public JavaCompatVisitor + { + public: + + TypesVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitClassDefEnd(const ClassDefPtr&); + virtual bool visitExceptionStart(const ExceptionPtr&); + virtual void visitExceptionEnd(const ExceptionPtr&); + virtual bool visitStructStart(const StructPtr&); + virtual void visitStructEnd(const StructPtr&); + virtual void visitDataMember(const DataMemberPtr&); + virtual void visitEnum(const EnumPtr&); + virtual void visitConst(const ConstPtr&); + + private: + + // + // Verifies that a data member method does not conflict with an operation. + // + bool validateMethod(const OperationList&, const std::string&, int, const std::string&, const std::string&); + }; + + class CompactIdVisitor : public JavaCompatVisitor + { + public: + + CompactIdVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + }; + + class HolderVisitor : public JavaCompatVisitor + { + public: + + HolderVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual bool visitStructStart(const StructPtr&); + virtual void visitSequence(const SequencePtr&); + virtual void visitDictionary(const DictionaryPtr&); + virtual void visitEnum(const EnumPtr&); + + private: + + void writeHolder(const TypePtr&); + }; + + class HelperVisitor : public JavaCompatVisitor + { + public: + + HelperVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitSequence(const SequencePtr&); + virtual void visitDictionary(const DictionaryPtr&); + + private: + + void writeOperation(const ClassDefPtr&, const std::string&, const OperationPtr&, bool); + }; + + class ProxyVisitor : public JavaCompatVisitor + { + public: + + ProxyVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitClassDefEnd(const ClassDefPtr&); + virtual void visitOperation(const OperationPtr&); + }; + + class DispatcherVisitor : public JavaCompatVisitor + { + public: + + DispatcherVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + }; + + class BaseImplVisitor : public JavaCompatVisitor + { + public: + + BaseImplVisitor(const std::string&); + + protected: + + // + // Generate code to emit a local variable declaration and initialize it + // if necessary. + // + void writeDecl(::IceUtilInternal::Output&, const std::string&, const std::string&, const TypePtr&, + const StringList&, bool); + + // + // Generate code to return a value. + // + void writeReturn(::IceUtilInternal::Output&, const TypePtr&, bool); + + // + // Generate an operation. + // + void writeOperation(::IceUtilInternal::Output&, const std::string&, const OperationPtr&, bool); + }; + + class ImplVisitor : public BaseImplVisitor + { + public: + + ImplVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + }; + + class ImplTieVisitor : public BaseImplVisitor + { + public: + + ImplTieVisitor(const std::string&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + }; + + class AsyncVisitor : public JavaCompatVisitor + { + public: + + AsyncVisitor(const std::string&); + + virtual void visitOperation(const OperationPtr&); + }; +}; + +} + +#endif diff --git a/cpp/src/slice2java/Main.cpp b/cpp/src/slice2java/Main.cpp index 7b9737d98a2..aba738cfaa3 100644 --- a/cpp/src/slice2java/Main.cpp +++ b/cpp/src/slice2java/Main.cpp @@ -15,6 +15,7 @@ #include <Slice/FileTracker.h> #include <Slice/Util.h> #include <Gen.h> +#include <GenCompat.h> #include <iterator> using namespace std; @@ -81,6 +82,7 @@ usage(const char* n) "--underscore Allow underscores in Slice identifiers.\n" "--checksum CLASS Generate checksums for Slice definitions into CLASS.\n" "--meta META Define global metadata directive META.\n" + "--compat Use the backward-compatible language mapping.\n" ; } @@ -108,7 +110,7 @@ compile(int argc, char* argv[]) opts.addOpt("", "underscore"); opts.addOpt("", "checksum", IceUtilInternal::Options::NeedArg); opts.addOpt("", "meta", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); - + opts.addOpt("", "compat"); bool validate = false; for(int i = 0; i < argc; ++i) @@ -193,6 +195,8 @@ compile(int argc, char* argv[]) vector<string> v = opts.argVec("meta"); copy(v.begin(), v.end(), back_inserter(globalMetadata)); + bool compat = opts.isSet("compat"); + if(args.empty()) { getErrorStream() << argv[0] << ": error: no input file" << endl; @@ -213,6 +217,16 @@ compile(int argc, char* argv[]) return EXIT_FAILURE; } + if(!compat && (tie || implTie)) + { + getErrorStream() << argv[0] << ": error: TIE classes are only supported with the Java-Compat mapping" << endl; + if(!validate) + { + usage(argv[0]); + } + return EXIT_FAILURE; + } + if(depend && dependxml) { getErrorStream() << argv[0] << ": error: cannot specify both --depend and --depend-xml" << endl; @@ -241,6 +255,13 @@ compile(int argc, char* argv[]) out.os() << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dependencies>" << endl; } + vector<string> cppOpts; + cppOpts.push_back("-D__SLICE2JAVA__"); + if(compat) + { + cppOpts.push_back("-D__SLICE2JAVA_COMPAT__"); + } + for(vector<string>::const_iterator i = args.begin(); i != args.end(); ++i) { // @@ -255,7 +276,7 @@ compile(int argc, char* argv[]) if(depend || dependxml) { PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs); - FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2JAVA__"); + FILE* cppHandle = icecpp->preprocess(false, cppOpts); if(cppHandle == 0) { @@ -273,8 +294,8 @@ compile(int argc, char* argv[]) return EXIT_FAILURE; } - if(!icecpp->printMakefileDependencies(out.os(), depend ? Preprocessor::Java : Preprocessor::SliceXML, includePaths, - "-D__SLICE2JAVA__")) + if(!icecpp->printMakefileDependencies(out.os(), depend ? Preprocessor::Java : Preprocessor::SliceXML, + includePaths, cppOpts)) { out.cleanup(); return EXIT_FAILURE; @@ -297,7 +318,7 @@ compile(int argc, char* argv[]) FileTracker::instance()->setSource(*i); PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs); - FILE* cppHandle = icecpp->preprocess(true, "-D__SLICE2JAVA__"); + FILE* cppHandle = icecpp->preprocess(true, cppOpts); if(cppHandle == 0) { @@ -348,31 +369,55 @@ compile(int argc, char* argv[]) { try { - Gen gen(argv[0], icecpp->getBaseName(), includePaths, output); - gen.generate(p); - if(tie) - { - gen.generateTie(p); - } - if(impl) + if(compat) { - gen.generateImpl(p); + GenCompat gen(argv[0], icecpp->getBaseName(), includePaths, output); + gen.generate(p); + if(tie) + { + gen.generateTie(p); + } + if(impl) + { + gen.generateImpl(p); + } + if(implTie) + { + gen.generateImplTie(p); + } + if(!checksumClass.empty()) + { + // + // Calculate checksums for the Slice definitions in the unit. + // + ChecksumMap m = createChecksums(p); + copy(m.begin(), m.end(), inserter(checksums, checksums.begin())); + } + if(listGenerated) + { + FileTracker::instance()->setOutput(os.str(), false); + } } - if(implTie) - { - gen.generateImplTie(p); - } - if(!checksumClass.empty()) - { - // - // Calculate checksums for the Slice definitions in the unit. - // - ChecksumMap m = createChecksums(p); - copy(m.begin(), m.end(), inserter(checksums, checksums.begin())); - } - if(listGenerated) + else { - FileTracker::instance()->setOutput(os.str(), false); + Gen gen(argv[0], icecpp->getBaseName(), includePaths, output); + gen.generate(p); + if(impl) + { + gen.generateImpl(p); + } + if(!checksumClass.empty()) + { + // + // Calculate checksums for the Slice definitions in the unit. + // + ChecksumMap m = createChecksums(p); + copy(m.begin(), m.end(), inserter(checksums, checksums.begin())); + } + if(listGenerated) + { + FileTracker::instance()->setOutput(os.str(), false); + } } } catch(const Slice::FileException& ex) @@ -423,8 +468,9 @@ compile(int argc, char* argv[]) } catch(const Slice::FileException& ex) { - // If a file could not be created, then - // cleanup any created files. + // + // If a file could not be created, then cleanup any created files. + // FileTracker::instance()->cleanup(); getErrorStream() << argv[0] << ": error: " << ex.reason() << endl; return EXIT_FAILURE; |