thrift/compiler/generate/t_mstch_java2_generator.cc (1,057 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed 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.
*/
#include <cctype>
#include <set>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <thrift/compiler/lib/java/util.h>
#include <thrift/compiler/ast/t_typedef.h>
#include <thrift/compiler/gen/cpp/type_resolver.h>
#include <thrift/compiler/generate/t_mstch_generator.h>
#include <thrift/compiler/generate/t_mstch_objects.h>
using namespace std;
namespace apache {
namespace thrift {
namespace compiler {
namespace {
/**
* Gets the java namespace, throws a runtime error if not found.
*/
std::string get_namespace_or_default(const t_program& prog) {
const auto& prog_namespace = prog.get_namespace("java2");
if (prog_namespace != "") {
return prog_namespace;
} else {
throw std::runtime_error{"No namespace 'java2' in " + prog.name()};
}
}
std::string get_constants_class_name(const t_program& prog) {
const auto& constant_name = prog.get_namespace("java2.constants");
if (constant_name == "") {
return "Constants";
} else {
auto java_name_space = get_namespace_or_default(prog);
std::string java_class_name;
if (constant_name.rfind(java_name_space) == 0) {
java_class_name = constant_name.substr(java_name_space.length() + 1);
} else {
java_class_name = constant_name;
}
if (java_class_name == "" ||
java_class_name.find('.') != std::string::npos) {
throw std::runtime_error{
"Java Constants Class Name `" + java_class_name +
"` is not well formatted."};
}
return java_class_name;
}
}
template <typename Node>
std::string get_java2_swift_name(const Node* node) {
return node->get_annotation(
"java.swift.name", java::mangle_java_name(node->get_name(), false));
}
} // namespace
class t_mstch_java2_generator : public t_mstch_generator {
public:
t_mstch_java2_generator(
t_program* program,
t_generation_context context,
const std::map<std::string, std::string>& parsed_options,
const std::string& /* option_string */)
: t_mstch_generator(
program, std::move(context), "java2", parsed_options) {
out_dir_base_ = "gen-java2";
}
void generate_program() override;
private:
void set_mstch_generators();
/*
* Generate multiple Java items according to the given template. Writes
* output to package_dir underneath the global output directory.
*/
template <typename T, typename Generator, typename Cache>
void generate_rpc_interfaces(
Generator const* generator,
Cache& c,
const t_program* program,
const std::vector<T*>& items) {
const auto& id = program->path();
if (!cache_->programs_.count(id)) {
cache_->programs_[id] = generators_->program_generator_->generate(
program, generators_, cache_);
}
auto package_dir = boost::filesystem::path{
java::package_to_path(get_namespace_or_default(*program))};
for (const T* item : items) {
auto filename = java::mangle_java_name(item->get_name(), true) + ".java";
const auto& item_id = id + item->get_name();
if (!c.count(item_id)) {
c[item_id] = generator->generate(item, generators_, cache_);
}
render_to_file(
c[item_id], "Service", "services" / package_dir / filename);
}
}
template <typename T, typename Generator, typename Cache>
void generate_items(
Generator const* generator,
Cache& c,
const t_program* program,
const std::vector<T*>& items,
const std::string& tpl_path) {
const auto& id = program->path();
if (!cache_->programs_.count(id)) {
cache_->programs_[id] = generators_->program_generator_->generate(
program, generators_, cache_);
}
auto package_dir = boost::filesystem::path{
java::package_to_path(get_namespace_or_default(*program))};
for (const T* item : items) {
auto filename = java::mangle_java_name(item->get_name(), true) + ".java";
const auto& item_id = id + item->get_name();
if (!c.count(item_id)) {
c[item_id] = generator->generate(item, generators_, cache_);
}
render_to_file(
c[item_id], tpl_path, "data-type" / package_dir / filename);
}
}
/*
* Generate Service Client implementation - Sync & Async. Writes
* output to package_dir
*/
template <typename T, typename Generator, typename Cache>
void generate_services(
Generator const* generator,
Cache& c,
const t_program* program,
const std::vector<T*>& services) {
const auto& id = program->path();
if (!cache_->programs_.count(id)) {
cache_->programs_[id] = generators_->program_generator_->generate(
program, generators_, cache_);
}
auto package_dir = boost::filesystem::path{
java::package_to_path(get_namespace_or_default(*program))};
// Iterate through services
for (const T* service : services) {
auto service_name = java::mangle_java_name(service->get_name(), true);
// Generate Async to Reactive Wrapper
auto async_reactive_wrapper_filename =
service_name + "AsyncReactiveWrapper.java";
const auto& async_reactive_wrapper_id =
id + service->get_name() + "AsyncReactiveWrapper";
if (!c.count(async_reactive_wrapper_id)) {
c[async_reactive_wrapper_id] =
generator->generate(service, generators_, cache_);
}
render_to_file(
c[async_reactive_wrapper_id],
"AsyncReactiveWrapper",
"services" / package_dir / async_reactive_wrapper_filename);
// Generate Blocking to Reactive Wrapper
auto blocking_reactive_wrapper_filename =
service_name + "BlockingReactiveWrapper.java";
const auto& blocking_reactive_wrapper_id =
id + service->get_name() + "BlockingReactiveWrapper";
if (!c.count(blocking_reactive_wrapper_id)) {
c[blocking_reactive_wrapper_id] =
generator->generate(service, generators_, cache_);
}
render_to_file(
c[blocking_reactive_wrapper_id],
"BlockingReactiveWrapper",
"services" / package_dir / blocking_reactive_wrapper_filename);
// Generate Reactive to Async Wrapper
auto reactive_async_wrapper_filename =
service_name + "ReactiveAsyncWrapper.java";
const auto& reactive_async_wrapper_id =
id + service->get_name() + "ReactiveAsyncWrapper";
if (!c.count(reactive_async_wrapper_id)) {
c[reactive_async_wrapper_id] =
generator->generate(service, generators_, cache_);
}
render_to_file(
c[reactive_async_wrapper_id],
"ReactiveAsyncWrapper",
"services" / package_dir / reactive_async_wrapper_filename);
// Generate Reactive to Blocking Wrapper
auto reactive_blocking_wrapper_filename =
service_name + "ReactiveBlockingWrapper.java";
const auto& reactive_blocking_wrapper_id =
id + service->get_name() + "ReactiveBlockingWrapper";
if (!c.count(reactive_blocking_wrapper_id)) {
c[reactive_blocking_wrapper_id] =
generator->generate(service, generators_, cache_);
}
render_to_file(
c[reactive_blocking_wrapper_id],
"ReactiveBlockingWrapper",
"services" / package_dir / reactive_blocking_wrapper_filename);
// Generate Reactive Client
auto reactive_client_filename = service_name + "ReactiveClient.java";
const auto& reactive_client_wrapper_id =
id + service->get_name() + "ReactiveClient";
if (!c.count(reactive_client_wrapper_id)) {
c[reactive_client_wrapper_id] =
generator->generate(service, generators_, cache_);
}
render_to_file(
c[reactive_client_wrapper_id],
"ReactiveClient",
"services" / package_dir / reactive_client_filename);
// Generate RpcServerHandler
auto rpc_server_handler_filename = service_name + "RpcServerHandler.java";
const auto& rpc_server_handler_id =
id + service->get_name() + "RpcServerHandler";
if (!c.count(rpc_server_handler_id)) {
c[rpc_server_handler_id] =
generator->generate(service, generators_, cache_);
}
render_to_file(
c[rpc_server_handler_id],
"RpcServerHandler",
"services" / package_dir / rpc_server_handler_filename);
}
}
void generate_constants(const t_program* program) {
if (program->consts().empty()) {
// Only generate Constants.java if we actually have constants
return;
}
auto name = program->name();
const auto& prog = cached_program(program);
auto package_dir = boost::filesystem::path{
java::package_to_path(get_namespace_or_default(*program))};
auto constant_file_name = get_constants_class_name(*program) + ".java";
render_to_file(
prog, "Constants", "data-type" / package_dir / constant_file_name);
}
void generate_placeholder(const t_program* program) {
auto package_dir = boost::filesystem::path{
java::package_to_path(get_namespace_or_default(*program))};
auto placeholder_file_name = ".generated_" + program->name();
write_output("data-type" / package_dir / placeholder_file_name, "");
write_output("services" / package_dir / placeholder_file_name, "");
}
};
class mstch_java2_program : public mstch_program {
public:
mstch_java2_program(
t_program const* program,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: mstch_program(program, generators, cache, pos) {
register_methods(
this,
{
{"program:javaPackage", &mstch_java2_program::java_package},
{"program:constantClassName",
&mstch_java2_program::constant_class_name},
});
}
mstch::node java_package() { return get_namespace_or_default(*program_); }
mstch::node constant_class_name() {
return get_constants_class_name(*program_);
}
};
class mstch_java2_struct : public mstch_struct {
// A struct is a "big struct" if it contains > 127 members. The reason for
// this limit is that we generate exhaustive constructor for Thrift struct
// but Java methods are limited to 255 arguments (and since long/double
// types count twice, 127 is a safe threshold).
static constexpr uint64_t bigStructThreshold = 127;
public:
mstch_java2_struct(
t_struct const* strct,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: mstch_struct(strct, generators, cache, pos) {
register_methods(
this,
{
{"struct:javaPackage", &mstch_java2_struct::java_package},
{"struct:unionFieldTypeUnique?",
&mstch_java2_struct::is_union_field_type_unique},
{"struct:asBean?", &mstch_java2_struct::is_as_bean},
{"struct:isBigStruct?", &mstch_java2_struct::is_BigStruct},
{"struct:javaCapitalName", &mstch_java2_struct::java_capital_name},
{"struct:javaAnnotations?",
&mstch_java2_struct::has_java_annotations},
{"struct:isUnion?", &mstch_java2_struct::is_struct_union},
{"struct:javaAnnotations", &mstch_java2_struct::java_annotations},
{"struct:exceptionMessage", &mstch_java2_struct::exception_message},
{"struct:needsExceptionMessage?",
&mstch_java2_struct::needs_exception_message},
{"struct:enableIsSet?", &mstch_java2_struct::enable_is_set},
});
}
mstch::node java_package() {
return get_namespace_or_default(*(strct_->program()));
}
mstch::node is_struct_union() { return strct_->is_union(); }
mstch::node is_union_field_type_unique() {
std::set<std::string> field_types;
for (const auto& field : strct_->fields()) {
auto type_name = field.type()->get_full_name();
std::string type_with_erasure = type_name.substr(0, type_name.find('<'));
if (field_types.find(type_with_erasure) != field_types.end()) {
return false;
} else {
field_types.insert(type_with_erasure);
}
}
return true;
}
mstch::node is_as_bean() {
if (!strct_->is_xception() && !strct_->is_union()) {
return strct_->get_annotation("java.swift.mutable") == "true";
} else {
return false;
}
}
mstch::node is_BigStruct() {
return (
strct_->is_struct() && strct_->fields().size() > bigStructThreshold);
}
mstch::node java_capital_name() {
return java::mangle_java_name(strct_->get_name(), true);
}
mstch::node has_java_annotations() {
return strct_->has_annotation("java.swift.annotations");
}
mstch::node java_annotations() {
return strct_->get_annotation("java.swift.annotations");
}
mstch::node exception_message() {
const auto& field_name_to_use = strct_->get_annotation("message");
if (const auto* field = strct_->get_field_by_name(field_name_to_use)) {
return get_java2_swift_name(field);
}
throw std::runtime_error{
"The exception message field '" + field_name_to_use +
"' is not found in " + strct_->get_name() + "!"};
}
// we can only override Throwable's getMessage() if:
// 1 - there is provided 'message' annotation
// 2 - there is no struct field named 'message'
// (since it will generate getMessage() as well)
mstch::node needs_exception_message() {
return strct_->is_xception() && strct_->has_annotation("message") &&
strct_->get_field_by_name("message") == nullptr;
}
mstch::node enable_is_set() {
return strct_->has_annotation("java.swift.enable_is_set");
}
};
class mstch_java2_service : public mstch_service {
public:
mstch_java2_service(
t_service const* service,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: mstch_service(service, generators, cache, pos) {
register_methods(
this,
{
{"service:javaPackage", &mstch_java2_service::java_package},
{"service:javaCapitalName",
&mstch_java2_service::java_capital_name},
{"service:onewayFunctions",
&mstch_java2_service::get_oneway_functions},
{"service:requestResponseFunctions",
&mstch_java2_service::get_request_response_functions},
{"service:singleRequestFunctions",
&mstch_java2_service::get_single_request_functions},
{"service:streamingFunctions",
&mstch_java2_service::get_streaming_functions},
{"service:sinkFunctions", &mstch_java2_service::get_sink_functions},
});
}
mstch::node java_package() {
return get_namespace_or_default(*(service_->program()));
}
mstch::node java_capital_name() {
return java::mangle_java_name(service_->get_name(), true);
}
mstch::node get_oneway_functions() {
std::vector<t_function*> funcs;
for (auto func : service_->get_functions()) {
if (func->is_oneway()) {
funcs.push_back(func);
}
}
return generate_functions(funcs);
}
mstch::node get_request_response_functions() {
std::vector<t_function*> funcs;
for (auto func : service_->get_functions()) {
if (!func->returns_stream() && !func->returns_sink() &&
!func->get_returntype()->is_service() && !func->is_oneway()) {
funcs.push_back(func);
}
}
return generate_functions(funcs);
}
mstch::node get_single_request_functions() {
std::vector<t_function*> funcs;
for (auto func : service_->get_functions()) {
if (!func->returns_stream() && !func->returns_sink() &&
!func->get_returntype()->is_service()) {
funcs.push_back(func);
}
}
return generate_functions(funcs);
}
mstch::node get_streaming_functions() {
std::vector<t_function*> funcs;
for (auto func : service_->get_functions()) {
if (func->returns_stream()) {
funcs.push_back(func);
}
}
return generate_functions(funcs);
}
mstch::node get_sink_functions() {
std::vector<t_function*> funcs;
for (auto func : service_->get_functions()) {
if (func->returns_sink()) {
funcs.push_back(func);
}
}
return generate_functions(funcs);
}
};
class mstch_java2_function : public mstch_function {
public:
mstch_java2_function(
t_function const* function,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: mstch_function(function, generators, cache, pos) {
register_methods(
this,
{
{"function:javaName", &mstch_java2_function::java_name},
{"function:voidType", &mstch_java2_function::is_void_type},
{"function:nestedDepth", &mstch_java2_function::get_nested_depth},
{"function:nestedDepth++",
&mstch_java2_function::increment_nested_depth},
{"function:nestedDepth--",
&mstch_java2_function::decrement_nested_depth},
{"function:isFirstDepth?", &mstch_java2_function::is_first_depth},
{"function:prevNestedDepth",
&mstch_java2_function::preceding_nested_depth},
{"function:isNested?",
&mstch_java2_function::get_nested_container_flag},
{"function:setIsNested",
&mstch_java2_function::set_nested_container_flag},
{"function:unsetIsNested",
&mstch_java2_function::unset_nested_container_flag},
});
}
int32_t nestedDepth = 0;
bool isNestedContainerFlag = false;
mstch::node get_nested_depth() { return nestedDepth; }
mstch::node preceding_nested_depth() { return (nestedDepth - 1); }
mstch::node is_first_depth() { return (nestedDepth == 1); }
mstch::node get_nested_container_flag() { return isNestedContainerFlag; }
mstch::node set_nested_container_flag() {
isNestedContainerFlag = true;
return mstch::node();
}
mstch::node unset_nested_container_flag() {
isNestedContainerFlag = false;
return mstch::node();
}
mstch::node increment_nested_depth() {
nestedDepth++;
return mstch::node();
}
mstch::node decrement_nested_depth() {
nestedDepth--;
return mstch::node();
}
mstch::node java_name() {
return java::mangle_java_name(function_->get_name(), false);
}
mstch::node is_void_type() { return function_->get_returntype()->is_void(); }
};
class mstch_java2_field : public mstch_field {
public:
mstch_java2_field(
t_field const* field,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos,
int32_t index,
field_generator_context const* field_context)
: mstch_field(field, generators, cache, pos, index, field_context) {
register_methods(
this,
{{"field:javaName", &mstch_java2_field::java_name},
{"field:javaCapitalName", &mstch_java2_field::java_capital_name},
{"field:javaDefaultValue", &mstch_java2_field::java_default_value},
{"field:javaAllCapsName", &mstch_java2_field::java_all_caps_name},
{"field:recursive?", &mstch_java2_field::is_recursive_reference},
{"field:negativeId?", &mstch_java2_field::is_negative_id},
{"field:javaAnnotations?", &mstch_java2_field::has_java_annotations},
{"field:javaAnnotations", &mstch_java2_field::java_annotations},
{"field:javaTFieldName", &mstch_java2_field::java_tfield_name},
{"field:isNullableOrOptionalNotEnum?",
&mstch_java2_field::is_nullable_or_optional_not_enum},
{"field:nestedDepth", &mstch_java2_field::get_nested_depth},
{"field:nestedDepth++", &mstch_java2_field::increment_nested_depth},
{"field:nestedDepth--", &mstch_java2_field::decrement_nested_depth},
{"field:isFirstDepth?", &mstch_java2_field::is_first_depth},
{"field:prevNestedDepth", &mstch_java2_field::preceding_nested_depth},
{"field:isContainer?", &mstch_java2_field::is_container},
{"field:isNested?", &mstch_java2_field::get_nested_container_flag},
{"field:setIsNested", &mstch_java2_field::set_nested_container_flag},
{"field:typeFieldName", &mstch_java2_field::type_field_name},
{"field:isSensitive?", &mstch_java2_field::is_sensitive},
{"field:hasInitialValue?", &mstch_java2_field::has_initial_value},
{"field:isPrimitive?", &mstch_java2_field::is_primitive},
{"field:adapterClassName",
&mstch_java2_field::get_structured_adapter_class_name},
{"field:typeClassName",
&mstch_java2_field::get_structured_type_class_name},
{"field:hasAdapter?", &mstch_java2_field::is_typedef_adapter}});
}
int32_t nestedDepth = 0;
bool isNestedContainerFlag = false;
mstch::node is_typedef_adapter() {
auto type = field_->get_type();
if (type->is_typedef()) {
auto has_annotation = type->find_structured_annotation_or_null(
"facebook.com/thrift/annotation/java/Adapter");
return has_annotation != nullptr;
} else {
return false;
}
}
mstch::node get_structured_adapter_class_name() {
return get_structed_annotation_attribute("adapterClassName");
}
mstch::node get_structured_type_class_name() {
return get_structed_annotation_attribute("typeClassName");
}
mstch::node get_structed_annotation_attribute(const std::string& field) {
auto type = field_->get_type();
if (auto annotation = type->find_structured_annotation_or_null(
"facebook.com/thrift/annotation/java/Adapter")) {
for (const auto& item : annotation->value()->get_map()) {
if (item.first->get_string() == field) {
return item.second->get_string();
}
}
}
return nullptr;
}
mstch::node has_initial_value() {
if (field_->get_req() == t_field::e_req::optional) {
// default values are ignored for optional fields
return false;
}
return field_->get_value();
}
mstch::node get_nested_depth() { return nestedDepth; }
mstch::node preceding_nested_depth() { return (nestedDepth - 1); }
mstch::node is_first_depth() { return (nestedDepth == 1); }
mstch::node get_nested_container_flag() { return isNestedContainerFlag; }
mstch::node set_nested_container_flag() {
isNestedContainerFlag = true;
return mstch::node();
}
mstch::node increment_nested_depth() {
nestedDepth++;
return mstch::node();
}
mstch::node decrement_nested_depth() {
nestedDepth--;
return mstch::node();
}
mstch::node is_primitive() {
auto type = field_->get_type()->get_true_type();
return type->is_void() || type->is_bool() || type->is_byte() ||
type->is_i16() || type->is_i32() || type->is_i64() ||
type->is_double() || type->is_float();
}
mstch::node is_nullable_or_optional_not_enum() {
if (field_->get_req() == t_field::e_req::optional) {
return true;
}
const t_type* field_type = field_->get_type()->get_true_type();
return !(
field_type->is_bool() || field_type->is_byte() ||
field_type->is_float() || field_type->is_i16() ||
field_type->is_i32() || field_type->is_i64() ||
field_type->is_double() || field_type->is_enum());
}
mstch::node is_container() {
return field_->get_type()->get_true_type()->is_container();
}
mstch::node java_name() { return get_java2_swift_name(field_); }
mstch::node type_field_name() {
auto type_name = field_->get_type()->get_full_name();
return java::mangle_java_name(type_name, true);
}
mstch::node java_tfield_name() {
return constant_name(field_->get_name()) + "_FIELD_DESC";
}
mstch::node java_capital_name() {
return java::mangle_java_name(
field_->get_annotation("java.swift.name", &field_->get_name()), true);
}
mstch::node java_all_caps_name() {
auto field_name = field_->get_name();
boost::to_upper(field_name);
return field_name;
}
mstch::node java_default_value() { return default_value_for_field(field_); }
mstch::node is_recursive_reference() {
return field_->get_annotation("swift.recursive_reference") == "true";
}
mstch::node is_negative_id() { return field_->get_key() < 0; }
std::string default_value_for_field(const t_field* field) {
if (field_->get_req() == t_field::e_req::optional) {
return "null";
}
return default_value_for_type(field->get_type());
}
std::string default_value_for_type(const t_type* type) {
if (type->is_typedef()) {
auto typedef_type = dynamic_cast<const t_typedef*>(type)->get_type();
return default_value_for_type(typedef_type);
} else {
if (type->is_byte() || type->is_i16() || type->is_i32()) {
return "0";
} else if (type->is_i64()) {
return "0L";
} else if (type->is_float()) {
return "0.f";
} else if (type->is_double()) {
return "0.";
} else if (type->is_bool()) {
return "false";
} else if (type->is_enum()) {
// we use fromInteger(0) as default value as it may be null or the enum
// entry for 0.
auto javaNamespace = get_namespace_or_default(*(type->program()));
auto enumType = java::mangle_java_name(type->get_name(), true);
return javaNamespace + "." + enumType + ".fromInteger(0)";
}
return "null";
}
}
mstch::node has_java_annotations() {
return field_->has_annotation("java.swift.annotations");
}
mstch::node is_sensitive() {
return field_->has_annotation("java.sensitive");
}
std::string constant_name(string name) {
string constant_str;
bool is_first = true;
bool was_previous_char_upper = false;
for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
string::value_type character = (*iter);
bool is_upper = isupper(character);
if (is_upper && !is_first && !was_previous_char_upper) {
constant_str += '_';
}
constant_str += toupper(character);
is_first = false;
was_previous_char_upper = is_upper;
}
return constant_str;
}
mstch::node java_annotations() {
return field_->get_annotation("java.swift.annotations");
}
};
class mstch_java2_enum : public mstch_enum {
public:
mstch_java2_enum(
t_enum const* enm,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: mstch_enum(enm, generators, cache, pos) {
register_methods(
this,
{
{"enum:javaPackage", &mstch_java2_enum::java_package},
{"enum:javaCapitalName", &mstch_java2_enum::java_capital_name},
{"enum:skipEnumNameMap?",
&mstch_java2_enum::java_skip_enum_name_map},
});
}
mstch::node java_package() {
return get_namespace_or_default(*(enm_->program()));
}
mstch::node java_capital_name() {
return java::mangle_java_name(enm_->get_name(), true);
}
mstch::node java_skip_enum_name_map() {
return enm_->has_annotation("java.swift.skip_enum_name_map");
}
};
class mstch_java2_enum_value : public mstch_enum_value {
public:
mstch_java2_enum_value(
t_enum_value const* enm_value,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: mstch_enum_value(enm_value, generators, cache, pos) {
register_methods(
this,
{
{"enum_value:javaConstantName",
&mstch_java2_enum_value::java_constant_name},
});
}
mstch::node java_constant_name() {
return java::mangle_java_constant_name(enm_value_->get_name());
}
};
class mstch_java2_const : public mstch_const {
public:
mstch_java2_const(
t_const const* cnst,
t_const const* current_const,
t_type const* expected_type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos,
int32_t index,
t_field const* field)
: mstch_const(
cnst,
current_const,
expected_type,
generators,
cache,
pos,
index,
field) {
register_methods(
this,
{
{"constant:javaCapitalName", &mstch_java2_const::java_capital_name},
{"constant:javaFieldName", &mstch_java2_const::java_field_name},
{"constant:javaIgnoreConstant?",
&mstch_java2_const::java_ignore_constant},
});
}
mstch::node java_capital_name() {
return java::mangle_java_constant_name(cnst_->get_name());
}
mstch::node java_field_name() {
return java::mangle_java_name(field_->get_name(), true);
}
mstch::node java_ignore_constant() {
// we have to ignore constants if they are enums that we handled as ints, as
// we don't have the constant values to work with.
if (cnst_->get_type()->is_map()) {
t_map* map = (t_map*)cnst_->get_type();
if (map->get_key_type()->is_enum()) {
return map->get_key_type()->has_annotation(
"java.swift.skip_enum_name_map");
}
}
if (cnst_->get_type()->is_list()) {
t_list* list = (t_list*)cnst_->get_type();
if (list->get_elem_type()->is_enum()) {
return list->get_elem_type()->has_annotation(
"java.swift.skip_enum_name_map");
}
}
if (cnst_->get_type()->is_set()) {
t_set* set = (t_set*)cnst_->get_type();
if (set->get_elem_type()->is_enum()) {
return set->get_elem_type()->has_annotation(
"java.swift.skip_enum_name_map");
}
}
return mstch::node();
}
};
class mstch_java2_const_value : public mstch_const_value {
public:
mstch_java2_const_value(
t_const_value const* const_value,
t_const const* current_const,
t_type const* expected_type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index)
: mstch_const_value(
const_value,
current_const,
expected_type,
generators,
cache,
pos,
index) {
register_methods(
this,
{
{"value:quotedString", &mstch_java2_const_value::quote_java_string},
{"value:javaEnumValueName",
&mstch_java2_const_value::java_enum_value_name},
});
}
mstch::node quote_java_string() {
return java::quote_java_string(const_value_->get_string());
}
mstch::node java_enum_value_name() {
if (type_ == cv::CV_INTEGER && const_value_->is_enum()) {
const t_enum_value* enum_value = const_value_->get_enum_value();
if (enum_value != nullptr) {
return java::mangle_java_constant_name(enum_value->get_name());
}
return "fromInteger(" + std::to_string(const_value_->get_integer()) + ")";
}
return mstch::node();
}
bool same_type_as_expected() const override { return true; }
};
class mstch_java2_type : public mstch_type {
public:
mstch_java2_type(
t_type const* type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION const pos)
: mstch_type(type, generators, cache, pos) {
register_methods(
this,
{
{"type:primitive?", &mstch_java2_type::is_primitive},
{"type:isContainer?", &mstch_java2_type::is_container_type},
{"type:javaType", &mstch_java2_type::java_type},
{"type:setIsMapKey", &mstch_java2_type::set_is_map_key},
{"type:isMapKey?", &mstch_java2_type::get_map_key_flag},
{"type:setIsMapValue", &mstch_java2_type::set_is_map_value},
{"type:isMapValue?", &mstch_java2_type::get_map_value_flag},
{"type:isBinaryString?", &mstch_java2_type::is_binary_string},
{"type:setIsNotMap", &mstch_java2_type::set_is_not_map},
});
}
bool isMapValueFlag = false;
bool isMapKeyFlag = false;
mstch::node set_is_not_map() {
isMapValueFlag = false;
isMapKeyFlag = false;
return mstch::node();
}
mstch::node get_map_value_flag() { return isMapValueFlag; }
mstch::node get_map_key_flag() { return isMapKeyFlag; }
mstch::node set_is_map_value() {
isMapValueFlag = true;
return mstch::node();
}
mstch::node set_is_map_key() {
isMapKeyFlag = true;
return mstch::node();
}
mstch::node is_container_type() {
return type_->get_true_type()->is_container();
}
mstch::node is_primitive() {
return type_->is_void() || type_->is_bool() || type_->is_byte() ||
type_->is_i16() || type_->is_i32() || type_->is_i64() ||
type_->is_double() || type_->is_float();
}
mstch::node java_type() {
return type_->get_true_type()->get_annotation("java.swift.type");
}
mstch::node is_binary_string() {
return type_->get_true_type()->get_annotation("java.swift.binary_string");
}
};
class program_java2_generator : public program_generator {
public:
program_java2_generator() = default;
~program_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_program const* program,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t /*index*/) const override {
return std::make_shared<mstch_java2_program>(
program, generators, cache, pos);
}
};
class struct_java2_generator : public struct_generator {
public:
explicit struct_java2_generator() = default;
~struct_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_struct const* strct,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t /*index*/) const override {
return std::make_shared<mstch_java2_struct>(strct, generators, cache, pos);
}
};
class service_java2_generator : public service_generator {
public:
explicit service_java2_generator() = default;
~service_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_service const* service,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t /*index*/) const override {
return std::make_shared<mstch_java2_service>(
service, generators, cache, pos);
}
};
class function_java2_generator : public function_generator {
public:
function_java2_generator() = default;
~function_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_function const* function,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t /*index*/) const override {
return std::make_shared<mstch_java2_function>(
function, generators, cache, pos);
}
};
class field_java2_generator : public field_generator {
public:
field_java2_generator() = default;
~field_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_field const* field,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index,
field_generator_context const* field_context) const override {
return std::make_shared<mstch_java2_field>(
field, generators, cache, pos, index, field_context);
}
};
class enum_java2_generator : public enum_generator {
public:
explicit enum_java2_generator() = default;
~enum_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_enum const* enm,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t /*index*/) const override {
return std::make_shared<mstch_java2_enum>(enm, generators, cache, pos);
}
};
class enum_value_java2_generator : public enum_value_generator {
public:
enum_value_java2_generator() = default;
~enum_value_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_enum_value const* enm_value,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t /*index*/) const override {
return std::make_shared<mstch_java2_enum_value>(
enm_value, generators, cache, pos);
}
};
class type_java2_generator : public type_generator {
public:
type_java2_generator() = default;
~type_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_type const* type,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t /*index*/) const override {
return std::make_shared<mstch_java2_type>(type, generators, cache, pos);
}
};
class const_java2_generator : public const_generator {
public:
const_java2_generator() = default;
~const_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_const const* cnst,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index,
t_const const* current_const,
t_type const* expected_type,
t_field const* field) const override {
return std::make_shared<mstch_java2_const>(
cnst,
current_const,
expected_type,
generators,
cache,
pos,
index,
field);
}
};
class const_value_java2_generator : public const_value_generator {
public:
const_value_java2_generator() = default;
~const_value_java2_generator() override = default;
std::shared_ptr<mstch_base> generate(
t_const_value const* const_value,
std::shared_ptr<mstch_generators const> generators,
std::shared_ptr<mstch_cache> cache,
ELEMENT_POSITION pos,
int32_t index,
t_const const* current_const,
t_type const* expected_type) const override {
return std::make_shared<mstch_java2_const_value>(
const_value,
current_const,
expected_type,
generators,
cache,
pos,
index);
}
};
void t_mstch_java2_generator::generate_program() {
set_mstch_generators();
auto name = get_program()->name();
const auto& id = get_program()->path();
if (!cache_->programs_.count(id)) {
cache_->programs_[id] = generators_->program_generator_->generate(
get_program(), generators_, cache_);
}
generate_items(
generators_->struct_generator_.get(),
cache_->structs_,
get_program(),
get_program()->objects(),
"Object");
generate_rpc_interfaces(
generators_->service_generator_.get(),
cache_->services_,
get_program(),
get_program()->services());
generate_services(
generators_->service_generator_.get(),
cache_->services_,
get_program(),
get_program()->services());
generate_items(
generators_->enum_generator_.get(),
cache_->enums_,
get_program(),
get_program()->enums(),
"Enum");
generate_constants(get_program());
generate_placeholder(get_program());
}
void t_mstch_java2_generator::set_mstch_generators() {
generators_->set_program_generator(
std::make_unique<program_java2_generator>());
generators_->set_struct_generator(std::make_unique<struct_java2_generator>());
generators_->set_service_generator(
std::make_unique<service_java2_generator>());
generators_->set_function_generator(
std::make_unique<function_java2_generator>());
generators_->set_field_generator(std::make_unique<field_java2_generator>());
generators_->set_enum_generator(std::make_unique<enum_java2_generator>());
generators_->set_enum_value_generator(
std::make_unique<enum_value_java2_generator>());
generators_->set_type_generator(std::make_unique<type_java2_generator>());
generators_->set_const_generator(std::make_unique<const_java2_generator>());
generators_->set_const_value_generator(
std::make_unique<const_value_java2_generator>());
}
THRIFT_REGISTER_GENERATOR(mstch_java2, "Java", "");
} // namespace compiler
} // namespace thrift
} // namespace apache