diff options
Diffstat (limited to 'cpp/src/Slice/JavaUtil.cpp')
-rw-r--r-- | cpp/src/Slice/JavaUtil.cpp | 3068 |
1 files changed, 2656 insertions, 412 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); } |