VPP-120: add custom types support to jvpp

Generates java classes based on typeonly definitions
(hashcode, equals and toString methods are also included).

Adds JNI handling for request and reply messages
(also arrays of custom types).

Change-Id: I16f1cea17899704426aa083fad1cb800a8d115df
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
diff --git a/vpp-api/java/Makefile.am b/vpp-api/java/Makefile.am
index cdb8379..390562b 100644
--- a/vpp-api/java/Makefile.am
+++ b/vpp-api/java/Makefile.am
@@ -92,11 +92,13 @@
 	cp -rf @srcdir@/jvpp-core/* -t jvpp-core/
 	mkdir -p jvpp-core/target
 	cd jvpp-core \
-		&& mkdir -p dto future callfacade callback notification \
+		&& mkdir -p types dto future callfacade callback notification \
 		&& @srcdir@/jvpp/gen/jvpp_gen.py -i defs_vpp_papi.py --plugin_name core \
-		&& cp -rf dto future callfacade callback notification *.java -t $(packagedir_jvpp_core) \
-		&& rm -rf dto future callfacade callback notification *.java
+		&& cp -rf types dto future callfacade callback notification *.java -t $(packagedir_jvpp_core) \
+		&& rm -rf types dto future callfacade callback notification *.java
+
 	$(JAVAC) -classpath jvpp-registry/target -d jvpp-core/target jvpp-core/$(packagedir_jvpp_core)/*.java \
+		jvpp-core/$(packagedir_jvpp_core)/types/*.java \
 		jvpp-core/$(packagedir_jvpp_core)/dto/*.java \
 		jvpp-core/$(packagedir_jvpp_core)/callback/*.java \
 		jvpp-core/$(packagedir_jvpp_core)/notification/*.java \
diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java
new file mode 100644
index 0000000..d7f5039
--- /dev/null
+++ b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/LispAdjacencyTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its 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.
+ */
+
+package io.fd.vpp.jvpp.core.test;
+
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.JVppRegistryImpl;
+import io.fd.vpp.jvpp.core.JVppCoreImpl;
+import io.fd.vpp.jvpp.core.dto.LispAddDelAdjacency;
+import io.fd.vpp.jvpp.core.dto.LispAddDelLocalEid;
+import io.fd.vpp.jvpp.core.dto.LispAddDelLocatorSet;
+import io.fd.vpp.jvpp.core.dto.LispAddDelRemoteMapping;
+import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGet;
+import io.fd.vpp.jvpp.core.dto.LispAdjacenciesGetReply;
+import io.fd.vpp.jvpp.core.dto.LispEnableDisable;
+import io.fd.vpp.jvpp.core.future.FutureJVppCoreFacade;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ExecutionException;
+import java.util.logging.Logger;
+
+/**
+ * Tests lisp adjacency creation and read (custom vpe.api type support showcase).
+ */
+public class LispAdjacencyTest {
+
+    private static final Logger LOG = Logger.getLogger(LispAdjacencyTest.class.getName());
+
+    private static void enableLisp(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException {
+        final LispEnableDisable request = new LispEnableDisable();
+        request.isEn = 1;
+        jvpp.lispEnableDisable(request).toCompletableFuture().get();
+        LOG.info("Lisp enabled successfully");
+    }
+
+    private static void addLocatorSet(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException {
+        final LispAddDelLocatorSet request = new LispAddDelLocatorSet();
+        request.isAdd = 1;
+        request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8);
+        jvpp.lispAddDelLocatorSet(request).toCompletableFuture().get();
+        LOG.info("Locator set created successfully:" + request.toString());
+    }
+
+    private static void addLocalEid(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException {
+        final LispAddDelLocalEid request = new LispAddDelLocalEid();
+        request.isAdd = 1;
+        request.locatorSetName = "ls1".getBytes(StandardCharsets.UTF_8);
+        request.eid = new byte[] {1, 2, 1, 10};
+        request.eidType = 0; // ip4
+        request.vni = 0;
+        request.prefixLen = 32;
+        jvpp.lispAddDelLocalEid(request).toCompletableFuture().get();
+        LOG.info("Local EID created successfully:" + request.toString());
+    }
+
+    private static void addRemoteMapping(final FutureJVppCoreFacade jvpp)
+        throws ExecutionException, InterruptedException {
+        final LispAddDelRemoteMapping request = new LispAddDelRemoteMapping();
+        request.isAdd = 1;
+        request.vni = 0;
+        request.eid = new byte[] {1, 2, 1, 20};
+        request.eidLen = 32;
+        request.rlocNum = 1;
+        request.rlocs = new byte[] {1, 1, 1, 1, 2, 1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+        jvpp.lispAddDelRemoteMapping(request).toCompletableFuture().get();
+        LOG.info("Remote mapping created successfully:" + request.toString());
+    }
+
+    private static void addAdjacency(final FutureJVppCoreFacade jvpp) throws ExecutionException, InterruptedException {
+        final LispAddDelAdjacency request = new LispAddDelAdjacency();
+        request.isAdd = 1;
+        request.leid = new byte[] {1, 2, 1, 10};
+        request.leidLen = 32;
+        request.reid = new byte[] {1, 2, 1, 20};
+        request.reidLen = 32;
+        request.eidType = 0; // ip4
+        request.vni = 0;
+        jvpp.lispAddDelAdjacency(request).toCompletableFuture().get();
+        LOG.info("Lisp adjacency created successfully:" + request.toString());
+    }
+
+    private static void showAdjacencies(final FutureJVppCoreFacade jvpp)
+        throws ExecutionException, InterruptedException {
+        final LispAdjacenciesGetReply reply =
+            jvpp.lispAdjacenciesGet(new LispAdjacenciesGet()).toCompletableFuture().get();
+        LOG.info("Lisp adjacency received successfully:" + reply.toString());
+    }
+
+    private static void testAdjacency(final FutureJVppCoreFacade jvpp) throws Exception {
+        enableLisp(jvpp);
+        addLocatorSet(jvpp);
+        addLocalEid(jvpp);
+        addRemoteMapping(jvpp);
+        addAdjacency(jvpp);
+        showAdjacencies(jvpp);
+    }
+
+    private static void testFutureApi() throws Exception {
+        LOG.info("Create lisp adjacency test");
+        try (final JVppRegistry registry = new JVppRegistryImpl("LispAdjacencyTest");
+             final FutureJVppCoreFacade jvppFacade = new FutureJVppCoreFacade(registry, new JVppCoreImpl())) {
+            LOG.info("Successfully connected to VPP");
+
+            testAdjacency(jvppFacade);
+            LOG.info("Disconnecting...");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        testFutureApi();
+    }
+}
diff --git a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt
index 2c9c424..c1b0c5a 100644
--- a/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt
+++ b/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/Readme.txt
@@ -14,3 +14,4 @@
 FutureApiNotificationTest - Tests interface notifications using Future based JVpp facade
 FutureApiTest - Execution of more complex calls using Future based JVpp facade
 L2AclTest - Tests L2 ACL creation
+LispAdjacencyTest - Tests lisp adjacency creation and read (custom vpe.api type support showcase)
diff --git a/vpp-api/java/jvpp-core/jvpp_core.c b/vpp-api/java/jvpp-core/jvpp_core.c
index 8872ef5..83c0bb2 100644
--- a/vpp-api/java/jvpp-core/jvpp_core.c
+++ b/vpp-api/java/jvpp-core/jvpp_core.c
@@ -71,8 +71,8 @@
         vl_msg_api_set_handlers(VL_API_##N, #n,     \
                 vl_api_##n##_t_handler,             \
                 vl_noop_handler,                    \
-                vl_api_##n##_t_endian,              \
-                vl_api_##n##_t_print,               \
+                vl_noop_handler,              \
+                vl_noop_handler,               \
                 sizeof(vl_api_##n##_t), 1);
         foreach_api_reply_handler;
     #undef _
diff --git a/vpp-api/java/jvpp/gen/jvpp_gen.py b/vpp-api/java/jvpp/gen/jvpp_gen.py
index 80bb4b9..3be8382 100755
--- a/vpp-api/java/jvpp/gen/jvpp_gen.py
+++ b/vpp-api/java/jvpp/gen/jvpp_gen.py
@@ -19,6 +19,7 @@
 import sys
 import os
 
+from jvppgen import types_gen
 from jvppgen import callback_gen
 from jvppgen import notification_gen
 from jvppgen import dto_gen
@@ -37,7 +38,6 @@
 #
 # where
 # defs_api_vpp_papi.py - vpe.api in python format (generated by vppapigen)
-from jvppgen.util import vpp_2_jni_type_mapping
 
 parser = argparse.ArgumentParser(description='VPP Java API generator')
 parser.add_argument('-i', action="store", dest="inputfile")
@@ -47,7 +47,7 @@
 
 sys.path.append(".")
 
-print "args.inputfile %s" % args.inputfile
+print "Generating Java API for %s" % args.inputfile
 importdir = os.path.dirname(args.inputfile)
 print "importdir %s" % importdir
 inputfile = os.path.basename(args.inputfile)
@@ -60,13 +60,6 @@
 sys.path.append(importdir)
 cfg = importlib.import_module(inputfile, package=None)
 
-
-# FIXME: functions unsupported due to problems with vpe.api
-def is_supported(f_name):
-    return f_name not in {'vnet_ip4_fib_counters', 'vnet_ip6_fib_counters',
-            'lisp_adjacencies_get_reply', 'lisp_adjacencies_get'}
-
-
 def is_request_field(field_name):
     return field_name not in {'_vl_msg_id', 'client_index', 'context'}
 
@@ -86,60 +79,52 @@
 
 def get_types(t, filter):
     types_list = []
-    c_types_list = []
     lengths_list = []
     for i in t:
         if not filter(i[1]):
             continue
         if len(i) is 3:  # array type
-            types_list.append(vpp_2_jni_type_mapping[i[0]] + 'Array')
-            c_types_list.append(i[0] + '[]')
+            types_list.append(i[0] + '[]')
             lengths_list.append((i[2], False))
         elif len(i) is 4:  # variable length array type
-            types_list.append(vpp_2_jni_type_mapping[i[0]] + 'Array')
-            c_types_list.append(i[0] + '[]')
+            types_list.append(i[0] + '[]')
             lengths_list.append((i[3], True))
         else:  # primitive type
-            types_list.append(vpp_2_jni_type_mapping[i[0]])
-            c_types_list.append(i[0])
+            types_list.append(i[0])
             lengths_list.append((0, False))
-    return types_list, c_types_list, lengths_list
+    return types_list, lengths_list
 
 
-def get_definitions():
+def get_definitions(defs):
     # Pass 1
     func_list = []
     func_name = {}
-    for a in cfg.messages:
-        if not is_supported(a[0]):
-            continue
-
+    for a in defs:
         java_name = util.underscore_to_camelcase(a[0])
 
         # For replies include all the arguments except message_id
         if util.is_reply(java_name):
-            types, c_types, lengths = get_types(a[1:], is_response_field)
+            types, lengths = get_types(a[1:], is_response_field)
             func_name[a[0]] = dict(
                 [('name', a[0]), ('java_name', java_name),
                  ('args', get_args(a[1:], is_response_field)), ('full_args', get_args(a[1:], lambda x: True)),
-                 ('types', types), ('c_types', c_types), ('lengths', lengths)])
+                 ('types', types), ('lengths', lengths)])
         # For requests skip message_id, client_id and context
         else:
-            types, c_types, lengths = get_types(a[1:], is_request_field)
+            types, lengths = get_types(a[1:], is_request_field)
             func_name[a[0]] = dict(
                 [('name', a[0]), ('java_name', java_name),
                  ('args', get_args(a[1:], is_request_field)), ('full_args', get_args(a[1:], lambda x: True)),
-                 ('types', types), ('c_types', c_types), ('lengths', lengths)])
+                 ('types', types), ('lengths', lengths)])
 
         # Indexed by name
         func_list.append(func_name[a[0]])
     return func_list, func_name
 
 
-func_list, func_name = get_definitions()
-
 base_package = 'io.fd.vpp.jvpp'
 plugin_package = base_package + '.' + plugin_name
+types_package = 'types'
 dto_package = 'dto'
 callback_package = 'callback'
 notification_package = 'notification'
@@ -148,6 +133,11 @@
 callback_facade_package = 'callfacade'
 control_ping_class_fqn = "%s.%s.%s" % (plugin_package, dto_package, control_ping_class)
 
+types_list, types_name = get_definitions(cfg.types)
+
+types_gen.generate_types(types_list, plugin_package, types_package, inputfile)
+
+func_list, func_name = get_definitions(cfg.messages)
 dto_gen.generate_dtos(func_list, base_package, plugin_package, plugin_name.title(), dto_package, args.inputfile)
 jvpp_impl_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name, control_ping_class_fqn, dto_package, args.inputfile)
 callback_gen.generate_callbacks(func_list, base_package, plugin_package, plugin_name.title(), callback_package, dto_package, args.inputfile)
@@ -155,3 +145,5 @@
 jvpp_c_gen.generate_jvpp(func_list, plugin_name, args.inputfile)
 jvpp_future_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, future_package, args.inputfile)
 jvpp_callback_facade_gen.generate_jvpp(func_list, base_package, plugin_package, plugin_name.title(), dto_package, callback_package, notification_package, callback_facade_package, args.inputfile)
+
+print "Java API for %s generated successfully" % args.inputfile
diff --git a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
index 1235479..a043c94 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/dto_gen.py
@@ -280,7 +280,7 @@
     cls_name = camel_case_dto_name + dump_dto_suffix
     # using artificial type for fields, just to bypass the is_array check in base methods generators
     # the type is not really used
-    artificial_type = 'jstring'
+    artificial_type = 'u8'
 
     # In case of already existing artificial reply dump DTO, just update it
     # Used for sub-dump dtos
diff --git a/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py
new file mode 100644
index 0000000..4b03b31
--- /dev/null
+++ b/vpp-api/java/jvpp/gen/jvppgen/jni_gen.py
@@ -0,0 +1,291 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its 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.
+
+from string import Template
+
+import util
+
+variable_length_array_value_template = Template("""mp->${length_var_name}""")
+variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""")
+
+dto_field_id_template = Template("""
+    jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_name}", "${jni_signature}");""")
+
+default_dto_field_setter_template = Template("""
+    (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, mp->${c_name});
+""")
+
+variable_length_array_value_template = Template("""mp->${length_var_name}""")
+variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""")
+
+u16_dto_field_setter_template = Template("""
+    (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u16(mp->${c_name}));
+""")
+
+u32_dto_field_setter_template = Template("""
+    (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u32(mp->${c_name}));
+""")
+
+u64_dto_field_setter_template = Template("""
+    (*env)->Set${jni_setter}(env, ${object_name}, ${field_reference_name}FieldId, clib_net_to_host_u64(mp->${c_name}));
+""")
+
+u8_array_dto_field_setter_template = Template("""
+    jbyteArray ${field_reference_name} = (*env)->NewByteArray(env, ${field_length});
+    (*env)->SetByteArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const jbyte*)mp->${c_name});
+    (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+""")
+
+u16_array_dto_field_setter_template = Template("""
+    {
+        jshortArray ${field_reference_name} = (*env)->NewShortArray(env, ${field_length});
+        jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL);
+        unsigned int _i;
+        for (_i = 0; _i < ${field_length}; _i++) {
+            ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]);
+        }
+
+        (*env)->ReleaseShortArrayElements(env,  ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+        (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+    }
+""")
+
+u32_array_dto_field_setter_template = Template("""
+    {
+        jintArray ${field_reference_name} = (*env)->NewIntArray(env, ${field_length});
+        jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL);
+        unsigned int _i;
+        for (_i = 0; _i < ${field_length}; _i++) {
+            ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]);
+        }
+
+        (*env)->ReleaseIntArrayElements(env,  ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+        (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+    }
+""")
+
+# For each u64 array we get its elements. Then we convert values to host byte order.
+# All changes to  jlong* buffer are written to jlongArray (isCopy is set to NULL)
+u64_array_dto_field_setter_template = Template("""
+    {
+        jlongArray ${field_reference_name} = (*env)->NewLongArray(env, ${field_length});
+        jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL);
+        unsigned int _i;
+        for (_i = 0; _i < ${field_length}; _i++) {
+            ${field_reference_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]);
+        }
+
+        (*env)->ReleaseLongArrayElements(env,  ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+        (*env)->SetObjectField(env, ${object_name}, ${field_reference_name}FieldId, ${field_reference_name});
+    }
+""")
+
+dto_field_setter_templates = {'u8': default_dto_field_setter_template,
+                              'u16': u16_dto_field_setter_template,
+                              'u32': u32_dto_field_setter_template,
+                              'i32': u32_dto_field_setter_template,
+                              'u64': u64_dto_field_setter_template,
+                              'f64': default_dto_field_setter_template,  # fixme
+                              'u8[]': u8_array_dto_field_setter_template,
+                              'u16[]': u16_array_dto_field_setter_template,
+                              'u32[]': u32_array_dto_field_setter_template,
+                              'u64[]': u64_array_dto_field_setter_template
+                              }
+
+
+def jni_reply_handler_for_type(handler_name, ref_name, field_type, c_name, field_reference_name,
+                               field_name, field_length, is_variable_len_array, length_field_type,
+                               object_name="dto"):
+    """
+    Generates jni code that initializes a field of java object (dto or custom type).
+    To be used in reply message handlers.
+    :param field_type: type of the field to be initialized (as defined in vpe.api)
+    :param c_name: name of the message struct member that stores initialization value
+    :param field_reference_name: name of the field reference in generated code
+    :param field_name: name of the field (camelcase)
+    :param field_length: integer or name of variable that stores field length
+    :param object_name: name of the object to be initialized
+    """
+
+    # todo move validation to vppapigen
+    if field_type.endswith('[]') and field_length == '0':
+        raise Exception('Variable array \'%s\' defined in \'%s\' '
+                        'should have defined length (e.g. \'%s[%s_length]\''
+                        % (c_name, handler_name, c_name, c_name))
+
+    if is_variable_len_array:
+        length_var_name = field_length
+        field_length = variable_length_array_value_template.substitute(length_var_name=length_var_name)
+        if length_field_type != 'u8':  # we need net to host conversion:
+            field_length = variable_length_array_template.substitute(
+                    length_field_type=length_field_type, value=field_length)
+
+    # for retval don't generate setters
+    if util.is_retval_field(c_name):
+        return ""
+
+    jni_signature = util.jni_2_signature_mapping[field_type]
+    jni_setter = util.jni_field_accessors[field_type]
+
+    result = dto_field_id_template.substitute(
+            field_reference_name=field_reference_name,
+            field_name=field_name,
+            class_ref_name=ref_name,
+            jni_signature=jni_signature)
+
+    dto_setter_template = dto_field_setter_templates[field_type]
+
+    result += dto_setter_template.substitute(
+            jni_signature=jni_signature,
+            object_name=object_name,
+            field_reference_name=field_reference_name,
+            c_name=c_name,
+            jni_setter=jni_setter,
+            field_length=field_length)
+    return result
+
+
+request_field_identifier_template = Template("""
+    jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}");
+    ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId);
+    """)
+
+array_length_enforcement_template = Template("""
+        size_t max_size = ${field_length};
+        if (cnt > max_size) cnt = max_size;""")
+
+u8_struct_setter_template = Template("""
+    mp->${c_name} = ${field_reference_name};""")
+
+u16_struct_setter_template = Template("""
+    mp->${c_name} = clib_host_to_net_u16(${field_reference_name});""")
+
+u32_struct_setter_template = Template("""
+    mp->${c_name} = clib_host_to_net_u32(${field_reference_name});""")
+
+i32_struct_setter_template = Template("""
+    mp->${c_name} = clib_host_to_net_i32(${field_reference_name});!""")
+
+u64_struct_setter_template = Template("""
+    mp->${c_name} = clib_host_to_net_u64(${field_reference_name});""")
+
+array_length_enforcement_template = Template("""
+        size_t max_size = ${field_length};
+        if (cnt > max_size) cnt = max_size;""")
+
+u8_array_struct_setter_template = Template("""
+    if (${field_reference_name}) {
+        jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+        ${field_length_check}
+        (*env)->GetByteArrayRegion(env, ${field_reference_name}, 0, cnt, (jbyte *)mp->${c_name});
+    }
+""")
+
+u16_array_struct_setter_template = Template("""
+    jshort * ${field_reference_name}ArrayElements = (*env)->GetShortArrayElements(env, ${field_reference_name}, NULL);
+    if (${field_reference_name}) {
+        size_t _i;
+        jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+        ${field_length_check}
+        for (_i = 0; _i < cnt; _i++) {
+            mp->${c_name}[_i] = clib_host_to_net_u16(${field_reference_name}ArrayElements[_i]);
+        }
+    }
+    (*env)->ReleaseShortArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+    """)
+
+u32_array_struct_setter_template = Template("""
+    jint * ${field_reference_name}ArrayElements = (*env)->GetIntArrayElements(env, ${field_reference_name}, NULL);
+    if (${field_reference_name}) {
+        size_t _i;
+        jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+        ${field_length_check}
+        for (_i = 0; _i < cnt; _i++) {
+            mp->${c_name}[_i] = clib_host_to_net_u32(${field_reference_name}ArrayElements[_i]);
+        }
+    }
+    (*env)->ReleaseIntArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+    """)
+
+u64_array_struct_setter_template = Template("""
+    jlong * ${field_reference_name}ArrayElements = (*env)->GetLongArrayElements(env, ${field_reference_name}, NULL);
+    if (${field_reference_name}) {
+        size_t _i;
+        jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+        ${field_length_check}
+        for (_i = 0; _i < cnt; _i++) {
+            mp->${c_name}[_i] = clib_host_to_net_u64(${field_reference_name}ArrayElements[_i]);
+        }
+    }
+    (*env)->ReleaseLongArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
+    """)
+
+struct_setter_templates = {'u8': u8_struct_setter_template,
+                           'u16': u16_struct_setter_template,
+                           'u32': u32_struct_setter_template,
+                           'i32': u32_struct_setter_template,
+                           'u64': u64_struct_setter_template,
+                           'u8[]': u8_array_struct_setter_template,
+                           'u16[]': u16_array_struct_setter_template,
+                           'u32[]': u32_array_struct_setter_template,
+                           'u64[]': u64_array_struct_setter_template
+                           }
+
+
+def jni_request_binding_for_type(field_type, c_name, field_reference_name, field_name, field_length,
+                                 is_variable_len_array, object_name="request"):
+    """
+    Generates jni code that initializes C structure that corresponds to a field of java object
+    (dto or custom type). To be used in request message handlers.
+    :param field_type: type of the field to be initialized (as defined in vpe.api)
+    :param c_name: name of the message struct member to be initialized
+    :param field_reference_name: name of the field reference in generated code
+    :param field_name: name of the field (camelcase)
+    :param field_length: integer or name of variable that stores field length
+    :param object_name: name of the object to be initialized
+    """
+    # field identifiers
+    jni_type = util.vpp_2_jni_type_mapping[field_type]
+    jni_signature = util.jni_2_signature_mapping[field_type]
+    jni_getter = util.jni_field_accessors[field_type]
+
+    # field identifier
+    msg_initialization = request_field_identifier_template.substitute(
+            jni_type=jni_type,
+            field_reference_name=field_reference_name,
+            field_name=field_name,
+            jni_signature=jni_signature,
+            jni_getter=jni_getter,
+            object_name=object_name)
+
+    # field setter
+    field_length_check = ""
+
+    # check if we are processing variable length array:
+    if is_variable_len_array:
+        field_length = util.underscore_to_camelcase(field_length)
+
+    # enforce max length if array has fixed length or uses variable length syntax
+    if str(field_length) != "0":
+        field_length_check = array_length_enforcement_template.substitute(field_length=field_length)
+
+    struct_setter_template = struct_setter_templates[field_type]
+
+    msg_initialization += struct_setter_template.substitute(
+            c_name=c_name,
+            field_reference_name=field_reference_name,
+            field_length_check=field_length_check)
+
+    return msg_initialization
diff --git a/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
index d63acd6..1a35a6c 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py
@@ -17,6 +17,9 @@
 import os, util
 from string import Template
 
+import jni_gen
+
+
 def is_manually_generated(f_name, plugin_name):
     return f_name in {'control_ping_reply'}
 
@@ -54,6 +57,7 @@
     $delete_class_invocations
 }""")
 
+
 def generate_class_cache(func_list, plugin_name):
     class_references = []
     find_class_invocations = []
@@ -105,94 +109,10 @@
     jclass requestClass = (*env)->FindClass(env, "io/fd/vpp/jvpp/${plugin_name}/dto/${java_name_upper}");""")
 
 request_field_identifier_template = Template("""
-    jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, requestClass, "${java_name}", "${jni_signature}");
-    ${jni_type} ${java_name} = (*env)->Get${jni_getter}(env, request, ${java_name}FieldId);
+    jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${object_name}Class, "${field_name}", "${jni_signature}");
+    ${jni_type} ${field_reference_name} = (*env)->Get${jni_getter}(env, ${object_name}, ${field_reference_name}FieldId);
     """)
 
-u8_struct_setter_template = Template("""
-    mp->${c_name} = ${java_name};""")
-
-u16_struct_setter_template = Template("""
-    mp->${c_name} = clib_host_to_net_u16(${java_name});""")
-
-u32_struct_setter_template = Template("""
-    mp->${c_name} = clib_host_to_net_u32(${java_name});""")
-
-i32_struct_setter_template = Template("""
-    mp->${c_name} = clib_host_to_net_i32(${java_name});!""")
-
-u64_struct_setter_template = Template("""
-    mp->${c_name} = clib_host_to_net_u64(${java_name});""")
-
-fixed_array_length_enforcement_template = Template("""
-        size_t max_size = ${field_length};
-        if (cnt > max_size) cnt = max_size;""")
-
-u8_array_struct_setter_template = Template("""
-    if (${java_name}) {
-        jsize cnt = (*env)->GetArrayLength (env, ${java_name});
-        ${field_length_check}
-        (*env)->GetByteArrayRegion(env, ${java_name}, 0, cnt, (jbyte *)mp->${c_name});
-    }
-""")
-
-u16_array_struct_setter_template = Template("""
-    jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL);
-    if (${java_name}) {
-        size_t _i;
-        jsize cnt = (*env)->GetArrayLength (env, ${java_name});
-        ${field_length_check}
-        for (_i = 0; _i < cnt; _i++) {
-            mp->${c_name}[_i] = clib_host_to_net_u16(${java_name}ArrayElements[_i]);
-        }
-    }
-    (*env)->ReleaseShortArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0);
-    """)
-
-u32_array_struct_setter_template = Template("""
-    jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL);
-    if (${java_name}) {
-        size_t _i;
-        jsize cnt = (*env)->GetArrayLength (env, ${java_name});
-        ${field_length_check}
-        for (_i = 0; _i < cnt; _i++) {
-            mp->${c_name}[_i] = clib_host_to_net_u32(${java_name}ArrayElements[_i]);
-        }
-    }
-    (*env)->ReleaseIntArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0);
-    """)
-
-u64_array_struct_setter_template = Template("""
-    jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL);
-    if (${java_name}) {
-        size_t _i;
-        jsize cnt = (*env)->GetArrayLength (env, ${java_name});
-        ${field_length_check}
-        for (_i = 0; _i < cnt; _i++) {
-            mp->${c_name}[_i] = clib_host_to_net_u64(${java_name}ArrayElements[_i]);
-        }
-    }
-    (*env)->ReleaseLongArrayElements (env, ${java_name}, ${java_name}ArrayElements, 0);
-    """)
-
-vl_api_ip4_fib_counter_t_array_struct_setter_template = Template("""
-    // vl_api_ip4_fib_counter_t_array_field_setter_template FIXME""")
-
-vl_api_ip6_fib_counter_t_array_struct_setter_template = Template("""
-    // vl_api_ip6_fib_counter_t_array_field_setter_template FIXME""")
-
-struct_setter_templates = {'u8': u8_struct_setter_template,
-                          'u16': u16_struct_setter_template,
-                          'u32': u32_struct_setter_template,
-                          'i32': u32_struct_setter_template,
-                          'u64': u64_struct_setter_template,
-                          'u8[]': u8_array_struct_setter_template,
-                          'u16[]': u16_array_struct_setter_template,
-                          'u32[]': u32_array_struct_setter_template,
-                          'u64[]': u64_array_struct_setter_template,
-                          'vl_api_ip4_fib_counter_t[]': vl_api_ip4_fib_counter_t_array_struct_setter_template,
-                          'vl_api_ip6_fib_counter_t[]': vl_api_ip6_fib_counter_t_array_struct_setter_template
-                  }
 
 jni_impl_template = Template("""
 /**
@@ -200,13 +120,12 @@
  * Generated based on $inputfile preparsed data:
 $api_data
  */
-JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${java_name}0
+JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name}Impl_${field_name}0
 (JNIEnv * env, jclass clazz$args) {
     ${plugin_name}_main_t *plugin_main = &${plugin_name}_main;
     vl_api_${c_name}_t * mp;
     u32 my_context_id = vppjni_get_context_id (&jvpp_main);
     $request_class
-    $field_identifiers
 
     // create message:
     mp = vl_msg_api_alloc(sizeof(*mp));
@@ -215,7 +134,8 @@
     mp->client_index = plugin_main->my_client_index;
     mp->context = clib_host_to_net_u32 (my_context_id);
 
-    $struct_setters
+    $msg_initialization
+
     // send message:
     vl_msg_api_send_shmem (plugin_main->vl_input_queue, (u8 *)&mp);
     if ((*env)->ExceptionCheck(env)) {
@@ -235,8 +155,7 @@
 
         arguments = ''
         request_class = ''
-        field_identifiers = ''
-        struct_setters = ''
+        msg_initialization = ''
         f_name_uppercase = f_name.upper()
 
         if f['args']:
@@ -247,142 +166,29 @@
                     java_name_upper=camel_case_function_name_upper,
                     plugin_name=plugin_name)
 
-            # field identifiers
-            for t in zip(f['types'], f['args']):
-                jni_type = t[0]
-                java_field_name = util.underscore_to_camelcase(t[1])
-                jni_signature = util.jni_2_signature_mapping[jni_type]
-                jni_getter = util.jni_field_accessors[jni_type]
-                field_identifiers += request_field_identifier_template.substitute(
-                        jni_type=jni_type,
-                        java_name=java_field_name,
-                        jni_signature=jni_signature,
-                        jni_getter=jni_getter)
-
-            # field setters
-            for t in zip(f['c_types'], f['args'], f['lengths']):
-                c_type = t[0]
-                c_name = t[1]
-                field_length = t[2][0]
-                field_length_check = ""
-
-                # check if we are processing variable length array:
-                if t[2][1]:
-                    field_length = util.underscore_to_camelcase(t[2][0])
-
-                # enforce max length if array has fixed length or uses variable length syntax
-                if str(t[2][0]) != "0":
-                    field_length_check = fixed_array_length_enforcement_template.substitute(field_length=field_length)
-
-                java_field_name = util.underscore_to_camelcase(c_name)
-
-                struct_setter_template = struct_setter_templates[c_type]
-
-                struct_setters += struct_setter_template.substitute(
-                        c_name=c_name,
-                        java_name=java_field_name,
-                        field_length_check=field_length_check)
+            for t in zip(f['types'], f['args'], f['lengths']):
+                field_name = util.underscore_to_camelcase(t[1])
+                msg_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=t[1],
+                                                                           field_reference_name=field_name,
+                                                                           field_name=field_name,
+                                                                           field_length=t[2][0],
+                                                                           is_variable_len_array=t[2][1])
 
         jni_impl.append(jni_impl_template.substitute(
                 inputfile=inputfile,
                 api_data=util.api_message_to_javadoc(f),
-                java_name=camel_case_function_name,
+                field_reference_name=camel_case_function_name,
+                field_name=camel_case_function_name,
                 c_name_uppercase=f_name_uppercase,
                 c_name=f_name,
                 plugin_name=plugin_name,
                 java_plugin_name=plugin_name.title(),
                 request_class=request_class,
-                field_identifiers=field_identifiers,
-                struct_setters=struct_setters,
+                msg_initialization=msg_initialization,
                 args=arguments))
 
     return "\n".join(jni_impl)
 
-
-dto_field_id_template = Template("""
-    jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");""")
-
-default_dto_field_setter_template = Template("""
-    (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, mp->${c_name});
-""")
-
-variable_length_array_value_template = Template("""mp->${length_var_name}""")
-variable_length_array_template = Template("""clib_net_to_host_${length_field_type}(${value})""")
-
-u16_dto_field_setter_template = Template("""
-    (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u16(mp->${c_name}));
-""")
-
-u32_dto_field_setter_template = Template("""
-    (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u32(mp->${c_name}));
-""")
-
-u64_dto_field_setter_template = Template("""
-    (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, clib_net_to_host_u64(mp->${c_name}));
-""")
-
-u8_array_dto_field_setter_template = Template("""
-    jbyteArray ${java_name} = (*env)->NewByteArray(env, ${field_length});
-    (*env)->SetByteArrayRegion(env, ${java_name}, 0, ${field_length}, (const jbyte*)mp->${c_name});
-    (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name});
-""")
-
-u16_array_dto_field_setter_template = Template("""
-    {
-        jshortArray ${java_name} = (*env)->NewShortArray(env, ${field_length});
-        jshort * ${java_name}ArrayElements = (*env)->GetShortArrayElements(env, ${java_name}, NULL);
-        unsigned int _i;
-        for (_i = 0; _i < ${field_length}; _i++) {
-            ${java_name}ArrayElements[_i] = clib_net_to_host_u16(mp->${c_name}[_i]);
-        }
-
-        (*env)->ReleaseShortArrayElements(env,  ${java_name}, ${java_name}ArrayElements, 0);
-        (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name});
-    }
-""")
-
-u32_array_dto_field_setter_template = Template("""
-    {
-        jintArray ${java_name} = (*env)->NewIntArray(env, ${field_length});
-        jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL);
-        unsigned int _i;
-        for (_i = 0; _i < ${field_length}; _i++) {
-            ${java_name}ArrayElements[_i] = clib_net_to_host_u32(mp->${c_name}[_i]);
-        }
-
-        (*env)->ReleaseIntArrayElements(env,  ${java_name}, ${java_name}ArrayElements, 0);
-        (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name});
-    }
-""")
-
-# For each u64 array we get its elements. Then we convert values to host byte order.
-# All changes to  jlong* buffer are written to jlongArray (isCopy is set to NULL)
-u64_array_dto_field_setter_template = Template("""
-    {
-        jlongArray ${java_name} = (*env)->NewLongArray(env, ${field_length});
-        jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL);
-        unsigned int _i;
-        for (_i = 0; _i < ${field_length}; _i++) {
-            ${java_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]);
-        }
-
-        (*env)->ReleaseLongArrayElements(env,  ${java_name}, ${java_name}ArrayElements, 0);
-        (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name});
-    }
-""")
-
-dto_field_setter_templates = {'u8': default_dto_field_setter_template,
-                      'u16': u16_dto_field_setter_template,
-                      'u32': u32_dto_field_setter_template,
-                      'i32': u32_dto_field_setter_template,
-                      'u64': u64_dto_field_setter_template,
-                      'f64': default_dto_field_setter_template, #fixme
-                      'u8[]': u8_array_dto_field_setter_template,
-                      'u16[]': u16_array_dto_field_setter_template,
-                      'u32[]': u32_array_dto_field_setter_template,
-                      'u64[]': u64_array_dto_field_setter_template
-                      }
-
 # code fragment for checking result of the operation before sending request reply
 callback_err_handler_template = Template("""
     // for negative result don't send callback message but send error callback
@@ -418,6 +224,7 @@
     (*env)->CallVoidMethod(env, plugin_main->callbackObject, callbackMethod, dto);
 }""")
 
+
 def generate_msg_handlers(func_list, plugin_name, inputfile):
     handlers = []
     for f in func_list:
@@ -438,25 +245,20 @@
         dto_setters = ''
         err_handler = ''
         # dto setters
-        for t in zip(f['c_types'], f['types'], f['args'], f['lengths']):
-            c_type = t[0]
-            jni_type = t[1]
-            c_name = t[2]
-            field_length = t[3][0]
-
-            if jni_type.endswith('Array') and field_length == '0':
-                raise Exception('Variable array \'%s\' defined in message \'%s\' '
-                                'should have defined length (e.g. \'%s[%s_length]\''
-                                % (c_name, handler_name, c_name, c_name))
-
-            # check if we are processing variable length array
-            if t[3][1]:
-                length_var_name = t[3][0]
-                length_field_type = f['c_types'][f['args'].index(length_var_name)]
-                field_length = variable_length_array_value_template.substitute(length_var_name=length_var_name)
-                if length_field_type != 'u8':  # we need net to host conversion:
-                    field_length = variable_length_array_template.substitute(
-                        length_field_type=length_field_type, value=field_length)
+        for t in zip(f['types'], f['args'], f['lengths']):
+            c_name = t[1]
+            java_name = util.underscore_to_camelcase(c_name)
+            field_length = t[2][0]
+            is_variable_len_array = t[2][1]
+            length_field_type = None
+            if is_variable_len_array:
+                length_field_type = f['types'][f['args'].index(field_length)]
+            dto_setters += jni_gen.jni_reply_handler_for_type(handler_name=handler_name, ref_name=ref_name,
+                                                              field_type=t[0], c_name=t[1],
+                                                              field_reference_name=java_name,
+                                                              field_name=java_name, field_length=field_length,
+                                                              is_variable_len_array=is_variable_len_array,
+                                                              length_field_type=length_field_type)
 
             # for retval don't generate setters and generate retval check
             if util.is_retval_field(c_name):
@@ -465,24 +267,6 @@
                 )
                 continue
 
-            java_field_name = util.underscore_to_camelcase(c_name)
-            jni_signature = util.jni_2_signature_mapping[jni_type]
-            jni_setter = util.jni_field_accessors[jni_type]
-
-            dto_setters += dto_field_id_template.substitute(
-                    java_name=java_field_name,
-                    class_ref_name=ref_name,
-                    jni_signature=jni_signature)
-
-            dto_setter_template = dto_field_setter_templates[c_type]
-
-            dto_setters += dto_setter_template.substitute(
-                    java_name=java_field_name,
-                    jni_signature=jni_signature,
-                    c_name=c_name,
-                    jni_setter=jni_setter,
-                    field_length=field_length)
-
         handlers.append(msg_handler_template.substitute(
             inputfile=inputfile,
             api_data=util.api_message_to_javadoc(f),
diff --git a/vpp-api/java/jvpp/gen/jvppgen/types_gen.py b/vpp-api/java/jvpp/gen/jvppgen/types_gen.py
new file mode 100644
index 0000000..d12fb3d
--- /dev/null
+++ b/vpp-api/java/jvpp/gen/jvppgen/types_gen.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016 Cisco and/or its 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.
+
+import os
+from string import Template
+
+import util
+import jni_gen
+import dto_gen
+
+type_template = Template("""
+package $plugin_package.$type_package;
+
+/**
+ * <p>This class represents $c_type_name type definition.
+ * <br>It was generated by types_gen.py based on $inputfile preparsed data:
+ * <pre>
+$docs
+ * </pre>
+ */
+public final class $java_type_name {
+$fields
+$methods
+}
+""")
+
+field_template = Template("""    public $type $name;\n""")
+
+
+def generate_type_fields(type_definition):
+    """
+    Generates fields for class representing typeonly definition
+    :param type_definition: python representation of typeonly definition
+    :return: string representing class fields
+    """
+    fields = ""
+    for t in zip(type_definition['types'], type_definition['args']):
+        field_name = util.underscore_to_camelcase(t[1])
+        fields += field_template.substitute(type=util.jni_2_java_type_mapping[t[0]],
+                                            name=field_name)
+    return fields
+
+object_struct_setter_template = Template("""
+    {
+        jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
+        memset (&(mp->${c_name}), 0, sizeof (mp->${c_name}));
+        ${struct_initialization}
+    }
+""")
+
+object_array_struct_setter_template = Template("""
+    {
+        jclass ${field_reference_name}ArrayElementClass = (*env)->FindClass(env, "${class_FQN}");
+        if (${field_reference_name}) {
+            size_t _i;
+            jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
+            ${field_length_check}
+            for (_i = 0; _i < cnt; _i++) {
+                jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i);
+                memset (&(mp->${c_name}[_i]), 0, sizeof (mp->${c_name}[_i]));
+                ${struct_initialization}
+            }
+        }
+    }
+""")
+
+object_dto_field_setter_template = Template("""
+    {
+        jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
+        jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
+        jobject ${field_reference_name} = (*env)->NewObject(env, ${field_reference_name}Class,  ${field_reference_name}Constructor);
+        ${type_initialization}
+        (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name});
+    }
+""")
+
+object_array_dto_field_setter_template = Template("""
+    {
+        jclass ${field_reference_name}Class = (*env)->FindClass(env, "${class_FQN}");
+        jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
+        unsigned int _i;
+        for (_i = 0; _i < ${field_length}; _i++) {
+            jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
+            jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class,  ${field_reference_name}Constructor);
+            ${type_initialization}
+            (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
+        }
+        (*env)->SetObjectField(env, dto, ${field_reference_name}FieldId, ${field_reference_name});
+    }
+""")
+
+
+def generate_struct_initialization(type_def, c_name_prefix, object_name, indent):
+    struct_initialization = ""
+    # field identifiers
+    for t in zip(type_def['types'], type_def['args'], type_def['lengths']):
+        field_reference_name = "${c_name}" + util.underscore_to_camelcase_upper(t[1])
+        field_name = util.underscore_to_camelcase(t[1])
+        struct_initialization += jni_gen.jni_request_binding_for_type(field_type=t[0], c_name=c_name_prefix + t[1],
+                                                                     field_reference_name=field_reference_name,
+                                                                     field_name=field_name,
+                                                                     field_length=t[2][0],
+                                                                     is_variable_len_array=t[2][1],
+                                                                     object_name=object_name)
+    return indent + struct_initialization.replace('\n', '\n' + indent)
+
+
+def generate_type_setter(handler_name, type_def, c_name_prefix, object_name, indent):
+    type_initialization = ""
+    for t in zip(type_def['types'], type_def['args'], type_def['lengths']):
+        field_length = t[2][0]
+        is_variable_len_array = t[2][1]
+        length_field_type = None
+        if is_variable_len_array:
+            length_field_type = type_def['types'][type_def['args'].index(field_length)]
+        type_initialization += jni_gen.jni_reply_handler_for_type(handler_name=handler_name,
+                                                                  ref_name="${field_reference_name}",
+                                                                  field_type=t[0], c_name=c_name_prefix + t[1],
+                                                                  field_reference_name="${c_name}" + util.underscore_to_camelcase_upper(t[1]),
+                                                                  field_name=util.underscore_to_camelcase(t[1]),
+                                                                  field_length=field_length,
+                                                                  is_variable_len_array=is_variable_len_array,
+                                                                  length_field_type=length_field_type,
+                                                                  object_name=object_name)
+    return indent + type_initialization.replace('\n', '\n' + indent)
+
+
+def generate_types(types_list, plugin_package, types_package, inputfile):
+    """
+    Generates Java representation of custom types defined in api file.
+    """
+
+    #
+    if not types_list:
+        print "Skipping custom types generation (%s does not define custom types)." % inputfile
+        return
+
+    print "Generating custom types"
+
+    if not os.path.exists(types_package):
+        raise Exception("%s folder is missing" % types_package)
+
+    for type in types_list:
+        c_type_name = type['name']
+        java_type_name = util.underscore_to_camelcase_upper(type['name'])
+        dto_path = os.path.join(types_package, java_type_name + ".java")
+
+        fields = generate_type_fields(type)
+
+        dto_file = open(dto_path, 'w')
+        dto_file.write(type_template.substitute(plugin_package=plugin_package,
+                                                type_package=types_package,
+                                                c_type_name=c_type_name,
+                                                inputfile=inputfile,
+                                                docs=util.api_message_to_javadoc(type),
+                                                java_type_name=java_type_name,
+                                                fields=fields,
+                                                methods=dto_gen.generate_dto_base_methods(java_type_name, type)
+                                                ))
+
+        # update type mappings:
+        # todo fix vpe.api to use type_name instead of vl_api_type_name_t
+        type_name = "vl_api_" + c_type_name + "_t"
+        java_fqn = "%s.%s.%s" % (plugin_package, types_package, java_type_name)
+        util.vpp_2_jni_type_mapping[type_name] = "jobject"
+        util.vpp_2_jni_type_mapping[type_name + "[]"] = "jobjectArray"
+        util.jni_2_java_type_mapping[type_name] = java_fqn
+        util.jni_2_java_type_mapping[type_name + "[]"] = java_fqn + "[]"
+        jni_name = java_fqn.replace('.', "/")
+        jni_signature = "L" + jni_name + ";"
+        util.jni_2_signature_mapping[type_name] = "L" + jni_name + ";"
+        util.jni_2_signature_mapping[type_name + "[]"] = "[" + jni_signature
+        util.jni_field_accessors[type_name] = "ObjectField"
+        util.jni_field_accessors[type_name + "[]"] = "ObjectField"
+
+        jni_gen.struct_setter_templates[type_name] = Template(
+                object_struct_setter_template.substitute(
+                        c_name="${c_name}",
+                        field_reference_name="${field_reference_name}",
+                        class_FQN=jni_name,
+                        struct_initialization=generate_struct_initialization(type, "${c_name}.",
+                                                                           "${field_reference_name}", ' ' * 4))
+        )
+
+        jni_gen.struct_setter_templates[type_name+ "[]"] = Template(
+                object_array_struct_setter_template.substitute(
+                        c_name="${c_name}",
+                        field_reference_name="${field_reference_name}",
+                        field_length_check="${field_length_check}",
+                        class_FQN=jni_name,
+                        struct_initialization=generate_struct_initialization(type, "${c_name}[_i].",
+                                                                           "${field_reference_name}ArrayElement", ' ' * 8))
+        )
+
+        jni_gen.dto_field_setter_templates[type_name] = Template(
+                object_dto_field_setter_template.substitute(
+                        field_reference_name="${field_reference_name}",
+                        field_length="${field_length}",
+                        class_FQN=jni_name,
+                        type_initialization=generate_type_setter(c_type_name, type, "${c_name}.",
+                                                                 "${field_reference_name}", ' ' * 4))
+        )
+
+        jni_gen.dto_field_setter_templates[type_name + "[]"] = Template(
+                object_array_dto_field_setter_template.substitute(
+                        field_reference_name="${field_reference_name}",
+                        field_length="${field_length}",
+                        class_FQN=jni_name,
+                        type_initialization=generate_type_setter(c_type_name, type, "${c_name}[_i].",
+                                                                 "${field_reference_name}ArrayElement", ' ' * 8))
+        )
+
+        dto_file.flush()
+        dto_file.close()
+
diff --git a/vpp-api/java/jvpp/gen/jvppgen/util.py b/vpp-api/java/jvpp/gen/jvppgen/util.py
index 712f178..4d3fca3 100644
--- a/vpp-api/java/jvpp/gen/jvppgen/util.py
+++ b/vpp-api/java/jvpp/gen/jvppgen/util.py
@@ -65,78 +65,94 @@
             else:
                 return reply_suffix
 
-# http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
-jni_2_java_type_mapping = {'jbyte': 'byte',
-                           'jbyteArray': 'byte[]',
-                           'jchar': 'char',
-                           'jcharArray': 'char[]',
-                           'jshort': 'short',
-                           'jshortArray': 'short[]',
-                           'jint': 'int',
-                           'jintArray': 'int[]',
-                           'jlong': 'long',
-                           'jlongArray': 'long[]',
-                           'jdouble': 'double',
-                           'jdoubleArray': 'double[]',
-                           'jfloat': 'float',
-                           'jfloatArray': 'float[]',
-                           'void': 'void',
-                           'jstring': 'java.lang.String',
-                           'jobject': 'java.lang.Object',
-                           'jobjectArray': 'java.lang.Object[]'
-                           }
-
-# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures
-jni_2_signature_mapping = {'jbyte': 'B',
-                           'jbyteArray': '[B',
-                           'jchar': 'C',
-                           'jcharArray': '[C',
-                           'jshort': 'S',
-                           'jshortArray': '[S',
-                           'jint': 'I',
-                           'jintArray': '[I',
-                           'jlong': 'J',
-                           'jlongArray': '[J',
-                           'jdouble': 'D',
-                           'jdoubleArray': '[D',
-                           'jfloat': 'F',
-                           'jfloatArray': '[F'
-                           }
-
-# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines
-jni_field_accessors = {
-    'jbyte': 'ByteField',
-    'jbyteArray': 'ObjectField',
-    'jchar': 'CharField',
-    'jcharArray': 'ObjectField',
-    'jshort': 'ShortField',
-    'jshortArray': 'ObjectField',
-    'jint': 'IntField',
-    'jintArray': 'ObjectField',
-    'jlong': 'LongField',
-    'jlongArray': 'ObjectField',
-    'jdouble': 'DoubleField',
-    'jdoubleArray': 'ObjectField',
-    'jfloat': 'FloatField',
-    'jfloatArray': 'ObjectField'
-}
-
 # Mapping according to:
 # http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html
 #
 # Unsigned types are converted to signed java types that have the same size.
 # It is the API user responsibility to interpret them correctly.
+jni_2_java_type_mapping = {'u8': 'byte',
+                           'u8[]': 'byte[]',
+                           'i8': 'byte',
+                           'i8[]': 'byte[]',
+                           'u16': 'short',
+                           'u16[]': 'short[]',
+                           'i16': 'short',
+                           'i16[]': 'short[]',
+                           'u32': 'int',
+                           'u32[]': 'int[]',
+                           'i32': 'int',
+                           'i32[]': 'int[]',
+                           'u64': 'long',
+                           'u64[]': 'long[]',
+                           'i64': 'long',
+                           'i64[]': 'long[]',
+                           'f64': 'double',
+                           'f64[]': 'double[]'
+                           }
+
 vpp_2_jni_type_mapping = {'u8': 'jbyte',
+                          'u8[]': 'jbyteArray',
                           'i8': 'jbyte',
+                          'u8[]': 'jbyteArray',
                           'u16': 'jshort',
+                          'u16[]': 'jshortArray',
                           'i16': 'jshort',
+                          'i16[]': 'jshortArray',
                           'u32': 'jint',
+                          'u32[]': 'jintArray',
                           'i32': 'jint',
+                          'i32[]': 'jintArray',
                           'u64': 'jlong',
+                          'u64[]': 'longArray',
                           'i64': 'jlong',
-                          'f64': 'jdouble'
+                          'u64[]': 'longArray',
+                          'f64': 'jdouble',
+                          'f64[]': 'jdoubleArray'
                           }
 
+# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures
+jni_2_signature_mapping = {'u8': 'B',
+                           'u8[]': '[B',
+                           'i8': 'B',
+                           'i8[]': '[B',
+                           'u16': 'S',
+                           'u16[]': '[S',
+                           'i16': 'S',
+                           'i16[]': '[S',
+                           'u32': 'I',
+                           'u32[]': '[I',
+                           'i32': 'I',
+                           'i32[]': '[I',
+                           'u64': 'J',
+                           'u64[]': '[J',
+                           'i64': 'J',
+                           'i64[]': '[J',
+                           'f64': 'D',
+                           'f64[]': '[D'
+                           }
+
+# https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Get_type_Field_routines
+jni_field_accessors =  {'u8': 'ByteField',
+                        'u8[]': 'ObjectField',
+                        'i8': 'ByteField',
+                        'i8[]': 'ObjectField',
+                        'u16': 'ShortField',
+                        'u16[]': 'ObjectField',
+                        'i16': 'ShortField',
+                        'i16[]': 'ObjectField',
+                        'u32': 'IntField',
+                        'u32[]': 'ObjectField',
+                        'i32': 'IntField',
+                        'i32[]': 'ObjectField',
+                        'u64': 'LongField',
+                        'u64[]': 'ObjectField',
+                        'i64': 'LongField',
+                        'i64[]': 'ObjectField',
+                        'f64': 'DoubleField',
+                        'f64[]': 'ObjectField'
+                        }
+
+
 # vpe.api calls that do not follow naming conventions and have to be handled exceptionally when finding reply -> request mapping
 # FIXME in vpe.api
 unconventional_naming_rep_req = {