From d7902bf19d0c323f38706c02338bbe2442f483c3 Mon Sep 17 00:00:00 2001 From: henrique Date: Mon, 31 Mar 2014 16:21:37 +0200 Subject: [PATCH] THRIFT-2368 New option: reuse-objects for Java generator Patch: adam-aph --- compiler/cpp/src/generate/t_java_generator.cc | 92 ++++++++++++++----- lib/java/build.xml | 33 ++++++- .../test/org/apache/thrift/TestReuse.java | 60 ++++++++++++ test/ReuseObjects.thrift | 30 ++++++ 4 files changed, 190 insertions(+), 25 deletions(-) create mode 100644 lib/java/test/org/apache/thrift/TestReuse.java create mode 100644 test/ReuseObjects.thrift diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc index 414c519e..9019c48a 100644 --- a/compiler/cpp/src/generate/t_java_generator.cc +++ b/compiler/cpp/src/generate/t_java_generator.cc @@ -78,6 +78,9 @@ public: android_legacy_ = true; } + iter = parsed_options.find("reuse-objects"); + reuse_objects_ = (iter != parsed_options.end()); + out_dir_base_ = (bean_style_ ? "gen-javabean" : "gen-java"); } @@ -197,16 +200,19 @@ public: void generate_deserialize_set_element (std::ofstream& out, t_set* tset, std::string prefix="", + std::string obj="", bool has_metadata = true); void generate_deserialize_map_element (std::ofstream& out, t_map* tmap, std::string prefix="", + std::string obj="", bool has_metadata = true); void generate_deserialize_list_element (std::ofstream& out, t_list* tlist, std::string prefix="", + std::string obj="", bool has_metadata = true); void generate_serialize_field (std::ofstream& out, @@ -310,6 +316,7 @@ public: bool android_legacy_; bool java5_; bool sorted_containers_; + bool reuse_objects_; }; @@ -3079,9 +3086,17 @@ void t_java_generator::generate_deserialize_field(ofstream& out, void t_java_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { - out << - indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << - indent() << prefix << ".read(iprot);" << endl; + + if (reuse_objects_) { + indent(out) << "if (" << prefix << " == null) {" << endl; + indent_up(); + } + indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl; + if (reuse_objects_) { + indent_down(); + indent(out) << "}" << endl; + } + indent(out) << prefix << ".read(iprot);" << endl; } /** @@ -3126,7 +3141,14 @@ void t_java_generator::generate_deserialize_container(ofstream& out, } } - indent(out) << prefix << " = new " << type_name(ttype, false, true); + if (reuse_objects_) { + indent(out) << "if (" << prefix << " == null) {" << endl; + indent_up(); + } + + out << + indent() << prefix << " = new " << type_name(ttype, false, true); + // size the collection correctly if (sorted_containers_ && (ttype->is_map() || ttype->is_set())) { // TreeSet and TreeMap don't have any constructor which takes a capactity as an argument @@ -3138,21 +3160,17 @@ void t_java_generator::generate_deserialize_container(ofstream& out, << ");" << endl; } - // For loop iterates over elements - string i = tmp("_i"); - indent(out) << - "for (int " << i << " = 0; " << - i << " < " << obj << ".size" << "; " << - "++" << i << ")" << endl; - - scope_up(out); + if (reuse_objects_) { + indent_down(); + indent(out) << "}" << endl; + } if (ttype->is_map()) { - generate_deserialize_map_element(out, (t_map*)ttype, prefix, has_metadata); + generate_deserialize_map_element(out, (t_map*)ttype, prefix, obj, has_metadata); } else if (ttype->is_set()) { - generate_deserialize_set_element(out, (t_set*)ttype, prefix, has_metadata); + generate_deserialize_set_element(out, (t_set*)ttype, prefix, obj, has_metadata); } else if (ttype->is_list()) { - generate_deserialize_list_element(out, (t_list*)ttype, prefix, has_metadata); + generate_deserialize_list_element(out, (t_list*)ttype, prefix, obj, has_metadata); } scope_down(out); @@ -3176,14 +3194,24 @@ void t_java_generator::generate_deserialize_container(ofstream& out, */ void t_java_generator::generate_deserialize_map_element(ofstream& out, t_map* tmap, - string prefix, bool has_metadata) { + string prefix, + string obj, bool has_metadata) { string key = tmp("_key"); string val = tmp("_val"); t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); - indent(out) << declare_field(&fkey) << endl; - indent(out) << declare_field(&fval) << endl; + indent(out) << declare_field(&fkey, reuse_objects_, false) << endl; + indent(out) << declare_field(&fval, reuse_objects_, false) << endl; + + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << + "for (int " << i << " = 0; " << + i << " < " << obj << ".size" << "; " << + "++" << i << ")" << endl; + + scope_up(out); generate_deserialize_field(out, &fkey, "", has_metadata); generate_deserialize_field(out, &fval, "", has_metadata); @@ -3196,15 +3224,25 @@ void t_java_generator::generate_deserialize_map_element(ofstream& out, */ void t_java_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, - string prefix, bool has_metadata) { + string prefix, + string obj, bool has_metadata) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); - indent(out) << declare_field(&felem) << endl; + indent(out) << declare_field(&felem, reuse_objects_, false) << endl; + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << + "for (int " << i << " = 0; " << + i << " < " << obj << ".size" << "; " << + "++" << i << ")" << endl; + scope_up(out); + generate_deserialize_field(out, &felem, "", has_metadata); indent(out) << prefix << ".add(" << elem << ");" << endl; + } /** @@ -3212,12 +3250,21 @@ void t_java_generator::generate_deserialize_set_element(ofstream& out, */ void t_java_generator::generate_deserialize_list_element(ofstream& out, t_list* tlist, - string prefix, bool has_metadata) { + string prefix, + string obj, bool has_metadata) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); - indent(out) << declare_field(&felem) << endl; + indent(out) << declare_field(&felem, reuse_objects_, false) << endl; + // For loop iterates over elements + string i = tmp("_i"); + indent(out) << + "for (int " << i << " = 0; " << + i << " < " << obj << ".size" << "; " << + "++" << i << ")" << endl; + scope_up(out); + generate_deserialize_field(out, &felem, "", has_metadata); indent(out) << prefix << ".add(" << elem << ");" << endl; @@ -4529,6 +4576,7 @@ THRIFT_REGISTER_GENERATOR(java, "Java", " nocamel: Do not use CamelCase field accessors with beans.\n" " android_legacy: Do not use java.io.IOException(throwable) (available for Android 2.3 and above).\n" " java5: Generate Java 1.5 compliant code (includes android_legacy flag).\n" +" reuse-objects: Data objects will not be allocated, but existing instances will be used (read and write).\n" " sorted_containers:\n" " Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of set/map.\n" ) diff --git a/lib/java/build.xml b/lib/java/build.xml index 5545b8ca..66ffb1d2 100755 --- a/lib/java/build.xml +++ b/lib/java/build.xml @@ -47,6 +47,7 @@ + @@ -75,6 +76,7 @@ + @@ -123,7 +125,21 @@ - + + @@ -150,6 +166,7 @@ + @@ -161,11 +178,15 @@ - + - + + + + + @@ -254,6 +275,12 @@ + + + + + + diff --git a/lib/java/test/org/apache/thrift/TestReuse.java b/lib/java/test/org/apache/thrift/TestReuse.java new file mode 100644 index 00000000..db16c74a --- /dev/null +++ b/lib/java/test/org/apache/thrift/TestReuse.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.thrift; + +import java.util.HashSet; + +import junit.framework.TestCase; + +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TType; + +import thrift.test.Reuse; + +// Tests reusing objects for deserialization. +// +public class TestReuse extends TestStruct { + + public void testReuseObject() throws Exception { + TSerializer binarySerializer = new TSerializer(new TBinaryProtocol.Factory()); + TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory()); + + Reuse ru1 = new Reuse(); + HashSet hs1 = new HashSet(); + byte[] serBytes; + String st1 = new String("string1"); + String st2 = new String("string2"); + + ru1.setVal1(11); + ru1.setVal2(hs1); + ru1.addToVal2(st1); + + serBytes = binarySerializer.serialize(ru1); + + // update hash set after serialization + hs1.add(st2); + + binaryDeserializer.deserialize(ru1, serBytes); + + assertTrue( ru1.getVal2() == hs1 ); + assertTrue( hs1.size() == 2 ); + } + +} diff --git a/test/ReuseObjects.thrift b/test/ReuseObjects.thrift new file mode 100644 index 00000000..2dd6c6ec --- /dev/null +++ b/test/ReuseObjects.thrift @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// The java codegenerator has option to reuse objects for deserialization + +namespace java thrift.test + +include "ThriftTest.thrift" + +struct Reuse { + 1: i32 val1; + 2: set val2; +} + -- 2.17.1