diff --git a/Modules/Core/Convolution/CMakeLists.txt b/Modules/Core/Convolution/CMakeLists.txt
index 262a67e7781e527596f3897125a8e86763868c3e..23143bcc315c84768ab2620a984d5d1cc0030f4a 100644
--- a/Modules/Core/Convolution/CMakeLists.txt
+++ b/Modules/Core/Convolution/CMakeLists.txt
@@ -22,7 +22,7 @@ project(OTBConvolution)
 
 option(OTB_USE_FFTW "Download and compile FFTW third party (license change to GPLv2)" OFF)
 if (OTB_USE_FFTW)
-  message(NOTICE "/!\\ /!\\ /!\\ You are actually compiling OTB with FFTW. As FFTW is distributed under GNU GPLv2, OTB is now provided with GNU GPLv2 license /!\\ /!\\ /!\\ ")
+  message(AUTHOR_WARNING "/!\\ /!\\ /!\\ You are actually compiling OTB with FFTW. As FFTW is distributed under GNU GPLv2, OTB is now provided with GNU GPLv2 license /!\\ /!\\ /!\\ ")
 else()
   message(STATUS "Compiling with FFTW disabled, otbOverlapSaveConvolutionImageFilter will not be available")
 endif()
diff --git a/Modules/Core/Wrappers/QGIS/src/CMakeLists.txt b/Modules/Core/Wrappers/QGIS/src/CMakeLists.txt
index 5dcf0ceffd5c40d8efcc409fcb316f4e8bd5425e..db199d5964dcc2513b2d1ac2b16a57a102e70e97 100644
--- a/Modules/Core/Wrappers/QGIS/src/CMakeLists.txt
+++ b/Modules/Core/Wrappers/QGIS/src/CMakeLists.txt
@@ -42,17 +42,27 @@ set(generate_descriptor_cmd "$<TARGET_FILE:otbQgisDescriptor>")
 if(CMAKE_SKIP_RPATH AND "${CMAKE_SYSTEM_NAME}"  MATCHES "Linux")
   set(generate_descriptor_cmd "env;LD_LIBRARY_PATH=${OTB_BINARY_DIR}/lib;$<TARGET_FILE:otbQgisDescriptor>")
 endif()
+# generate dependency list
+# put all app into a file
+# same for dfiles
+set(QGIS_APP_LIST_FILE "${CMAKE_CURRENT_BINARY_DIR}/qgis_apps_list.txt")
+# if file does not exists it does not emit an error
+file(REMOVE "${QGIS_APP_LIST_FILE}")
+file(TOUCH "${QGIS_APP_LIST_FILE}")
+set(QGIS_APP_DESCRIPTOR_PATH "${OTB_BINARY_DIR}/${OTB_INSTALL_DATA_DIR}/description")
+
 foreach(app_name ${app_names})
   add_dependencies(otbQgisDescriptor otbapp_${app_name})
-  set(dfile "${OTB_BINARY_DIR}/${OTB_INSTALL_DATA_DIR}/description/${app_name}.txt")
-  add_custom_command(OUTPUT "${dfile}"
-    COMMAND ${generate_descriptor_cmd}
-    "${app_name}" "${app_location}" "./${OTB_INSTALL_DATA_DIR}/description/"
-    WORKING_DIRECTORY ${OTB_BINARY_DIR}
-    COMMENT "./bin/otbQgisDescriptor ${app_name} ${app_location} ./${OTB_INSTALL_DATA_DIR}/description/"
-    VERBATIM)
-  list(APPEND dfiles "${dfile}")
+  file(APPEND "${QGIS_APP_LIST_FILE}" "${app_name}\n")
 endforeach()
 
-add_custom_target(generate_descriptors DEPENDS ${dfiles} )
+# call otbQgisDescriptor with the app list, the location to create the files 
+add_custom_command(OUTPUT "${QGIS_APP_DESCRIPTOR_PATH}/algs.txt"
+  COMMAND ${generate_descriptor_cmd}
+  "${QGIS_APP_LIST_FILE}" "${app_location}" "./${OTB_INSTALL_DATA_DIR}/description/"
+  WORKING_DIRECTORY ${OTB_BINARY_DIR}
+  COMMENT "Generate gqis descriptor files"
+  VERBATIM)
+
+add_custom_target(generate_descriptors DEPENDS "${QGIS_APP_DESCRIPTOR_PATH}/algs.txt")
 add_dependencies(${otb-module}-all generate_descriptors)
diff --git a/Modules/Core/Wrappers/QGIS/src/otbQgisDescriptor.cxx b/Modules/Core/Wrappers/QGIS/src/otbQgisDescriptor.cxx
index 83fa26d184c67d61590e9158ae88186c4af618ea..1baaa8b3038ddf44960834ca49ba434d90c7df36 100644
--- a/Modules/Core/Wrappers/QGIS/src/otbQgisDescriptor.cxx
+++ b/Modules/Core/Wrappers/QGIS/src/otbQgisDescriptor.cxx
@@ -28,347 +28,401 @@
 #include <iostream>
 #include <cassert>
 #include <fstream>
+#include <regex>
 
-int main(int argc, char* argv[])
-{
-  if (argc < 3)
+#define QGIS_DEBUG 0
+
+using namespace otb::Wrapper;
+
+std::string getMandatoryOutputImageParam(const Application::Pointer app,
+                                         const std::vector<std::string>& app_keys) {
+  for (const std::string& app_key: app_keys)
   {
-    std::cerr << "Usage : " << argv[0] << " name OTB_APPLICATION_PATH [out_dir]" << std::endl;
-    return EXIT_FAILURE;
+    Parameter::Pointer param = app->GetParameterByKey(app_key);
+    if (param->GetMandatory() && param->GetType() == ParameterType_OutputImage)
+    {
+      return app_key;
+    }
   }
+  return ""; // if nothing found
+}
 
-  using namespace otb::Wrapper;
+std::string QGISLineFactory(const Application::Pointer app,
+                            const std::string& paramKey)
+{
+  static const std::unordered_map<ParameterType, std::string> parameterTypeToString {
+    {ParameterType_Bool, "QgsProcessingParameterBoolean"},
+    {ParameterType_Int, "QgsProcessingParameterNumber"},
+    {ParameterType_Float, "QgsProcessingParameterNumber"},
+    {ParameterType_Double, "QgsProcessingParameterNumber"},
+    {ParameterType_RAM, "QgsProcessingParameterNumber"},
+    {ParameterType_Radius, "QgsProcessingParameterNumber"},
+    {ParameterType_Choice, "OTBParameterChoice"},
+    {ParameterType_String, "QgsProcessingParameterString"},
+    {ParameterType_InputImage, "QgsProcessingParameterRasterLayer"},
+    {ParameterType_InputFilename, "QgsProcessingParameterFile"},
+    {ParameterType_InputImageList, "QgsProcessingParameterMultipleLayers"},
+    {ParameterType_InputVectorData, "QgsProcessingParameterVectorLayer"},
+    {ParameterType_InputFilenameList, "QgsProcessingParameterMultipleLayers"},
+    {ParameterType_InputVectorDataList, "QgsProcessingParameterMultipleLayers"},
+    {ParameterType_OutputImage, "QgsProcessingParameterRasterDestination"},
+    {ParameterType_OutputVectorData, "QgsProcessingParameterVectorDestination"},
+    {ParameterType_OutputFilename, "QgsProcessingParameterFileDestination"},
+    {ParameterType_Directory, "QgsProcessingParameterFile"},
+    {ParameterType_Field, "QgsProcessingParameterField"},
+    {ParameterType_Band, "QgsProcessingParameterBand"},
+    {ParameterType_StringList, "QgsProcessingParameterString"},
+    {ParameterType_ListView, "QgsProcessingParameterEnum"}
+  };
+
+  enum FilterType {
+    NONE = 0b00000000,
+    STRING = 0b00000001,
+    NUMERIC = 0b00000010,
+    MIXED = 0b00000011
+  };
+
+
+  std::ostringstream qgis_line;
+  const Parameter::Pointer param         (app->GetParameterByKey(paramKey));
+  ParameterType            type          (param->GetType());
+  const std::string        description   (app->GetParameterName(paramKey));
+  std::string              optional      ("True");
+  std::string              default_value ("None");
+
+
+  if (type == ParameterType_Group || type == ParameterType_RAM || param->GetRole() == Role_Output)
+  {
+    // group parameter cannot have any value.
+    // ram is added by qgis-otb processing provider plugin as an advanced parameter for all apps
+    // parameter role cannot be of type Role_Output
+    return "";
+  }
 
-  const std::string module(argv[1]);
+  // if there is no choice value for a list view parameter
+  // we switch to parameter stringlist to avoid aving empty combobox in QGIS
+  if (type == ParameterType_ListView && app->GetChoiceNames(paramKey).empty()) {
+    type = ParameterType_StringList;
+  }
 
-/* TestApplication is removed in CMakeLists.txt */
-#if 0
-  if (module == "TestApplication")
-    return EXIT_SUCCESS;
-#endif
 
-  ApplicationRegistry::AddApplicationPath(argv[2]);
-  Application::Pointer appli = ApplicationRegistry::CreateApplicationFaster(module);
-
-  assert(!appli.IsNull());
-
-  const std::string group = appli->GetDocTags().size() > 0 ? appli->GetDocTags()[0] : "";
-  assert(!group.empty());
-
-  std::map<ParameterType, std::string> parameterTypeToString;
-  parameterTypeToString[ParameterType_Bool]                = "QgsProcessingParameterBoolean";
-  parameterTypeToString[ParameterType_Int]                 = "QgsProcessingParameterNumber";
-  parameterTypeToString[ParameterType_Float]               = "QgsProcessingParameterNumber";
-  parameterTypeToString[ParameterType_Double]              = "QgsProcessingParameterNumber";
-  parameterTypeToString[ParameterType_RAM]                 = "QgsProcessingParameterNumber";
-  parameterTypeToString[ParameterType_Radius]              = "QgsProcessingParameterNumber";
-  parameterTypeToString[ParameterType_Choice]              = "OTBParameterChoice";
-  parameterTypeToString[ParameterType_String]              = "QgsProcessingParameterString";
-  parameterTypeToString[ParameterType_InputImage]          = "QgsProcessingParameterRasterLayer";
-  parameterTypeToString[ParameterType_InputFilename]       = "QgsProcessingParameterFile";
-  parameterTypeToString[ParameterType_InputImageList]      = "QgsProcessingParameterMultipleLayers";
-  parameterTypeToString[ParameterType_InputVectorData]     = "QgsProcessingParameterVectorLayer";
-  parameterTypeToString[ParameterType_InputFilenameList]   = "QgsProcessingParameterMultipleLayers";
-  parameterTypeToString[ParameterType_InputVectorDataList] = "QgsProcessingParameterMultipleLayers";
-  parameterTypeToString[ParameterType_OutputImage]         = "QgsProcessingParameterRasterDestination";
-  parameterTypeToString[ParameterType_OutputVectorData]    = "QgsProcessingParameterVectorDestination";
-  parameterTypeToString[ParameterType_OutputFilename]      = "QgsProcessingParameterFileDestination";
-  parameterTypeToString[ParameterType_Directory]           = "QgsProcessingParameterFile";
-  parameterTypeToString[ParameterType_Field]               = "QgsProcessingParameterField";
-  parameterTypeToString[ParameterType_Band]                = "QgsProcessingParameterBand";
-  // TODO
-  parameterTypeToString[ParameterType_StringList] = "QgsProcessingParameterString";
-
-  parameterTypeToString[ParameterType_ListView] = "QgsProcessingParameterEnum";
-
-  const std::vector<std::string> appKeyList = appli->GetParametersKeys(true);
-  const unsigned int             nbOfParam  = appKeyList.size();
-
-  std::string output_file = module + ".txt";
-  std::string algs_txt    = "algs.txt";
-  if (argc > 3)
+  auto it = parameterTypeToString.find(type);
+  if (it == parameterTypeToString.end())
   {
-    output_file = std::string(argv[3]) + module + ".txt";
-    algs_txt    = std::string(argv[3]) + "algs.txt";
+    // NOTE get also module name
+    throw std::runtime_error("No mapping found for parameter '" + paramKey +
+                             "' type=" + parameterTypesStrings[type]);
   }
-  std::ofstream dFile;
-  dFile.open(output_file, std::ios::out);
+  
+  std::string qgis_type = it->second;
 
-  std::string output_parameter_name;
-  bool        hasRasterOutput = false;
+  if (param->GetMandatory())
   {
-    for (unsigned int i = 0; i < nbOfParam; i++)
-    {
-      Parameter::Pointer param = appli->GetParameterByKey(appKeyList[i]);
-      if (param->GetMandatory())
-      {
-        if (appli->GetParameterType(appKeyList[i]) == ParameterType_OutputImage)
-        {
-          output_parameter_name = appKeyList[i];
-          hasRasterOutput       = true;
-        }
-      }
-    }
+    // TODO: avoid workaround for stringlist types (fix appengine)
+    // type == ParameterType_StringList check is needed because:
+    // If parameter is  mandatory it can have no value
+    // It is accepted in OTB that, string list could be generated dynamically
+    // qgis has no such option to handle dynamic values yet..
+    // So mandatory parameters whose type is StringList is considered optional
+    optional = param->HasValue() || type == ParameterType_StringList ? "True" : "False";
   }
 
-  if (output_parameter_name.empty())
-    dFile << module << std::endl;
-  else
-    dFile << module << "|" << output_parameter_name << std::endl;
 
-  dFile << appli->GetDescription() << std::endl;
-  dFile << group << std::endl;
+  bool isEpsgCode = false;
 
-  /*
-  From here onwards each line appended to dFile is passed to QgsProcessingParameter* class constructor.
-  dFile is nothing but a csv (with a .txt) with "|" as delimiter character.
-  First field is the name of Qgis parameter class and rest of it are extracted as list and passed to class constructor.
-  Parsing and calling of parameter classes are done by python.
-  source available : qgis/python/plugins/processing/core/parameters.py
-  source code of qgis parameter is available at: qgis/src/core/processing/qgsprocessingparameters.cpp
-  */
+  // use QgsProcessingParameterCrs if required.
+  // Check if paramKey == "epsg" only or epsg is one of the extensions
+  // use double \ to get one in final expression
+  const std::regex epsg_regex(".+\\.epsg\\..+");
+  if (paramKey == "epsg" || std::regex_match(paramKey, epsg_regex)) {
+    qgis_type  = "QgsProcessingParameterCrs";
+    isEpsgCode = true;
+  }
 
-  for (unsigned int i = 0; i < nbOfParam; i++)
-  {
-    const std::string        name        = appKeyList[i];
-    const Parameter::Pointer param       = appli->GetParameterByKey(name);
-    ParameterType            type        = appli->GetParameterType(name);
-    const std::string        description = appli->GetParameterName(name);
-
-    // if there is no choice value for a list view parameter
-    // we switch to parameter stringlist to avoid aving empty combobox in QGIS
-    if (type == ParameterType_ListView)
-    {
-      if ( appli->GetChoiceNames(name).empty() )
-      {
-        type = ParameterType_StringList;
-      }
-    }
+  qgis_line << qgis_type << "|" << paramKey << "|" << description;
 
-    std::string optional;
-    if (param->GetMandatory())
+  int filterType;
+  std::vector<std::string> name_list;
+  std::vector<std::string> key_list;
+  std::string values;
+  std::string proc_param_field;
+  ListViewParameter *lv_param;
+  ChoiceParameter* choiceParam;
+  FieldParameter* fieldParam;
+  BandParameter* bandParam;
+
+  switch (type)
+  {
+  case ParameterType_Int:
+    if (isEpsgCode)
     {
-      // TODO: avoid workaround for stringlist types (fix appengine)
-      // type == ParameterType_StringList check is needed because:
-      // If parameter is  mandatory it can have no value
-      // It is accepted in OTB that, string list could be generated dynamically
-      // qgis has no such option to handle dynamic values yet..
-      // So mandatory parameters whose type is StringList is considered optional
-      optional = param->HasValue() || type == ParameterType_StringList ? "True" : "False";
+      if (param->HasValue() && app->GetParameterInt(paramKey) < 1)
+        default_value = "EPSG: " + app->GetParameterAsString(paramKey);
+      else
+        default_value = "ProjectCrs";
     }
     else
     {
-      optional = "True";
+      qgis_line << "|QgsProcessingParameterNumber.Integer";
+      default_value = param->HasValue() ? app->GetParameterAsString(paramKey) : "0";
     }
-
-    if (type == ParameterType_Group || type == ParameterType_RAM || param->GetRole() == Role_Output)
+    break;
+  case ParameterType_Float:
+  case ParameterType_Double:
+    qgis_line << "|QgsProcessingParameterNumber.Double";
+    default_value = param->HasValue() ? app->GetParameterAsString(paramKey) : "0";
+    break;
+  case ParameterType_Radius:
+    qgis_line << "|QgsProcessingParameterNumber.Integer";
+    default_value = param->HasValue() ? app->GetParameterAsString(paramKey) : "0";
+    break;
+  case ParameterType_InputFilename:
+    // TODO: if parameter InputFilename can give supported extensions
+    // we can use it gitlab #1559
+    qgis_line << "|QgsProcessingParameterFile.File|None";
+    break;
+  case ParameterType_Directory:
+    qgis_line << "|QgsProcessingParameterFile.Folder|False";
+    break;
+  case ParameterType_InputImageList:
+    qgis_line << "|3"; // QgsProcessing.TypeRaster
+    break;
+  case ParameterType_InputVectorDataList:
+  case ParameterType_InputVectorData:
+  case ParameterType_OutputVectorData:
+    qgis_line << "|-1"; // QgsProcessing.TypeVectorAnyGeometry
+    break;
+  case ParameterType_InputFilenameList:
+    qgis_line << "|4"; // QgsProcessing.TypeFile"
+    break;
+  case ParameterType_String:
+    // Below line is interpreted in qgis processing as
+    // 1. default_value = None
+    // 2. multiLine = False
+    // For more details,
+    // please refer to documentation of QgsProcessingParameterString.
+    default_value = "None|False";
+    break;
+  case ParameterType_StringList:
+    // Below line is interpreted in qgis processing as
+    // 1. default_value = None
+    // 2. multiLine = True
+    // For more details,
+    // please refer to documentation of QgsProcessingParameterString.
+    // setting default_value this way is an exception for ParameterType_StringList and ParameterType_String
+    default_value = "None|True";
+    break;
+  case ParameterType_InputImage:
+  case ParameterType_OutputImage:
+    // default is None and nothing to add to qgis_line
+    break;
+  case ParameterType_OutputFilename:
+    // fileFilter and defaultValue is None
+    // OTB does not have any implementation for file extension.
+    default_value = "None|None";
+    break;
+  case ParameterType_ListView:
+    lv_param = dynamic_cast<ListViewParameter*>(param.GetPointer());
+    name_list  = app->GetChoiceNames(paramKey);
+    for( auto k : name_list)
+      values += k + ";";
+    values.pop_back();
+    qgis_line << "|" << values ;
+    qgis_line << "|" << (lv_param->GetSingleSelection() ? "False" : "True");
+    break;
+  case ParameterType_Bool:
+    default_value = app->GetParameterAsString(paramKey);
+    break;
+  case ParameterType_Choice:
+    key_list = app->GetChoiceKeys(paramKey);
+    for (auto k : key_list)
+      values += k + ";";
+
+    if (!values.empty())
+      values.pop_back();
+
+    qgis_line << "|" << values;
+    choiceParam = dynamic_cast<ChoiceParameter*>(param.GetPointer());
+    default_value           = std::to_string(choiceParam->GetValue());
+    break;
+  case ParameterType_Field:
+    fieldParam = dynamic_cast<FieldParameter*>(param.GetPointer());
+    filterType = FilterType::NONE;
+
+    for (auto type : fieldParam->GetTypeFilter())
     {
-      // group parameter cannot have any value.
-      // ram is added by qgis-otb processing provider plugin as an advanced parameter for all apps
-      // parameter role cannot be of type Role_Output
-      continue;
+      if (type == OFTString)
+      filterType |= FilterType::STRING;
+      else if (type == OFTInteger || type == OFTInteger64 || type == OFTReal)
+      filterType |= FilterType::NUMERIC;
     }
 
-    auto it = parameterTypeToString.find(type);
-    assert(it != parameterTypeToString.end());
-    if (it == parameterTypeToString.end())
-    {
-      std::cerr << "No mapping found for parameter '" << name << "' type=" << type << std::endl;
-      return EXIT_FAILURE;
-    }
-    std::string qgis_type = it->second;
+    if (filterType == FilterType::NONE || filterType == FilterType::MIXED)
+      proc_param_field = "QgsProcessingParameterField.Any";
+    else if (filterType == FilterType::STRING)
+      proc_param_field = "QgsProcessingParameterField.String";
+    else if (filterType == FilterType::NUMERIC)
+      proc_param_field = "QgsProcessingParameterField.Numeric";
+
+    qgis_line << "|None|"
+          << fieldParam->GetVectorData()
+          << "|" << proc_param_field
+          << "|" << (fieldParam->GetSingleSelection() ? "False" : "True")
+          << "|" << optional;
+    break;
+  case ParameterType_Band:
+    bandParam = dynamic_cast<BandParameter*>(param.GetPointer());
+
+    qgis_line << "|None|"
+          << bandParam->GetRasterData() << "|"
+          << optional
+          << "|" << (bandParam->GetSingleSelection() ? "False" : "True");
+    break;
+  default:
+    throw std::runtime_error("ERROR: default_value is empty for '" + paramKey +
+                             "' type='" + qgis_type  + "'");
+    break;
+  }
 
-    bool isEpsgCode = false;
+#if QGIS_DEBUG
+      std::cerr << paramKey;
+      std::cerr << " mandatory=" << param->GetMandatory();
+      std::cerr << " HasValue=" << param->HasValue();
+      std::cerr << " qgis_type=" << qgis_type;
+      std::cerr << " optional=" << optional << std::endl;
+#endif
 
-    // use QgsProcessingParameterCrs if required.
-    // TODO: do a regex on name to match ==epsg || *\.epsg.\*
-    if (name == "epsg" || name == "map.epsg.code" || name == "mapproj.epsg.code" || name == "mode.epsg.code")
-    {
-      qgis_type  = "QgsProcessingParameterCrs";
-      isEpsgCode = true;
-    }
+  // optional and default value are not in the same order than
+  // other QGis processing parameters for field and band
+  if (type != ParameterType_Field && type != ParameterType_Band)
+  {
+    qgis_line << "|" << default_value << "|" << optional;
+  }
 
-    dFile << qgis_type << "|" << name << "|" << description;
+  return qgis_line.str();
+}
 
-    std::string default_value = "None";
-    if (type == ParameterType_Int)
-    {
-      if (isEpsgCode)
-      {
-        if (param->HasValue() && appli->GetParameterInt(name) < 1)
-          default_value = "EPSG: " + appli->GetParameterAsString(name);
-        else
-          default_value = "ProjectCrs";
-      }
-      else
-      {
-        dFile << "|QgsProcessingParameterNumber.Integer";
-        default_value = param->HasValue() ? appli->GetParameterAsString(name) : "0";
-      }
-    }
-    else if (type == ParameterType_Float || type == ParameterType_Double)
-    {
-      dFile << "|QgsProcessingParameterNumber.Double";
-      default_value = param->HasValue() ? appli->GetParameterAsString(name) : "0";
-    }
-    else if (type == ParameterType_Radius)
-    {
-      dFile << "|QgsProcessingParameterNumber.Integer";
-      default_value = param->HasValue() ? appli->GetParameterAsString(name) : "0";
-    }
-    else if (type == ParameterType_InputFilename)
-    {
-      // TODO: if parameter InputFilename can give supported extensions
-      // we can use it gitlab #1559
-      dFile << "|QgsProcessingParameterFile.File|None";
-    }
-    else if (type == ParameterType_Directory)
-    {
-      dFile << "|QgsProcessingParameterFile.Folder|False";
-    }
-    else if (type == ParameterType_InputImageList)
-    {
-      dFile << "|3"; // QgsProcessing.TypeRaster
-    }
-    else if (type == ParameterType_InputVectorDataList || type == ParameterType_InputVectorData || type == ParameterType_OutputVectorData)
-    {
-      dFile << "|-1"; // QgsProcessing.TypeVectorAnyGeometry
-    }
-    else if (type == ParameterType_InputFilenameList)
-    {
-      dFile << "|4"; // QgsProcessing.TypeFile"
-    }
-    else if (type == ParameterType_String)
-    {
-      // Below line is interpreted in qgis processing as
-      // 1. default_value = None
-      // 2. multiLine = False
-      // For more details,
-      // please refer to documentation of QgsProcessingParameterString.
-      default_value = "None|False";
-    }
-    else if (type == ParameterType_StringList)
-    {
-      // Below line is interpreted in qgis processing as
-      // 1. default_value = None
-      // 2. multiLine = True
-      // For more details,
-      // please refer to documentation of QgsProcessingParameterString.
-      // setting default_value this way is an exception for ParameterType_StringList and ParameterType_String
-      default_value = "None|True";
-    }
-    else if (type == ParameterType_InputImage || type == ParameterType_OutputImage)
-    {
-      // default is None and nothing to add to dFile
-    }
-    else if (type == ParameterType_OutputFilename)
-    {
-      // fileFilter and defaultValue is None
-      // OTB does not have any implementation for file extension.
-      default_value = "None|None";
-    }
-    else if (type == ParameterType_ListView)
-    {
-        ListViewParameter *lv_param = dynamic_cast<ListViewParameter*>(param.GetPointer());
-	      std::vector<std::string>  name_list  = appli->GetChoiceNames(name);
-	      std::string values = "";
-	      for( auto k : name_list)
-          values += k + ";";
-	      values.pop_back();
-	      dFile << "|" << values ;
-        dFile << "|" << (lv_param->GetSingleSelection() ? "False" : "True");
-    }
-    else if (type == ParameterType_Bool)
-    {
-      default_value = appli->GetParameterAsString(name);
-    }
-    else if (type == ParameterType_Choice)
-    {
-      std::vector<std::string> key_list = appli->GetChoiceKeys(name);
-      std::string              values   = "";
-      for (auto k : key_list)
-        values += k + ";";
+void writeModuleQGISDescriptor(const Application::Pointer app,
+                               const std::string& module_name,
+                               const std::string& group,
+                               const std::string& descriptor_file_path) {
+  // RAII capsule to automatically close file when we are out of scope
+  // as this function is able to throw, we must ensure that the file is
+  // correctly closed
+  auto module_descriptor = std::unique_ptr<std::ofstream, std::function<void(std::ofstream*)>>(
+                              new std::ofstream(descriptor_file_path, std::ios::out),
+                              [](std::ofstream* o) { o->close(); }
+                           );
+
+  const std::vector<std::string> appKeyList = app->GetParametersKeys(true);
+
+  // --------------QGIS Module file header-----------------
+  // composed like following (line break included):
+  // <module name>|<mandatory output param name (if exists)>
+  // <description>
+  // <group>
+  const std::string mandatory_out_param_name = getMandatoryOutputImageParam(app, appKeyList);
+
+  // Add app name and mandatory output if it exists
+  if (mandatory_out_param_name.empty())
+    *module_descriptor << module_name << std::endl;
+  else
+    *module_descriptor << module_name << "|" << mandatory_out_param_name << std::endl;
 
-      if (!values.empty())
-        values.pop_back();
+  // add description and group
+  *module_descriptor << app->GetDescription() << std::endl;
+  *module_descriptor << group << std::endl;
 
-      dFile << "|" << values;
-      ChoiceParameter* cparam = dynamic_cast<ChoiceParameter*>(param.GetPointer());
-      default_value           = std::to_string(cparam->GetValue());
-    }
-    else if (type == ParameterType_Field)
-    {
-      FieldParameter *f_param = dynamic_cast<FieldParameter*>(param.GetPointer());
-
-      enum {
-            STRING = 1 << 0,
-            NUMERIC = 1 << 1
-      };
-
-      int filterType = 0;
-      for (auto type : f_param->GetTypeFilter())
-      {
-        if (type == OFTString)
-          filterType |= STRING;
-        else if (type == OFTInteger || type == OFTInteger64 || type == OFTReal)
-          filterType |= NUMERIC;
-      }
-
-      dFile << "|None|"
-            << f_param->GetVectorData()
-            << "|"  << (filterType == STRING  ? "QgsProcessingParameterField.String" :
-                        filterType == NUMERIC ? "QgsProcessingParameterField.Numeric" :
-                        "QgsProcessingParameterField.Any")
-            << "|" << (f_param->GetSingleSelection() ? "False" : "True")
-            << "|" << optional;
-    }
-    else if (type == ParameterType_Band)
-    {
-      BandParameter *f_param = dynamic_cast<BandParameter*>(param.GetPointer());
+  //-------------QGIS Module parameters part----------------
 
-      dFile << "|None|"
-            << f_param->GetRasterData() << "|"
-            << optional
-            << "|" << (f_param->GetSingleSelection() ? "False" : "True");
-    }
-    else
-    {
-      std::cout << "ERROR: default_value is empty for '" << name << "' type='" << qgis_type << "'" << std::endl;
-      return EXIT_FAILURE;
-    }
+  /*
+  From here onwards each line appended to module_descriptor is passed to QgsProcessingParameter* class constructor.
+  module_descriptor is nothing but a csv (with a .txt) with "|" as delimiter character.
+  First field is the name of Qgis parameter class and rest of it are extracted as list and passed to class constructor.
+  Parsing and calling of parameter classes are done by python.
+  source available : qgis/python/plugins/processing/core/parameters.py
+  source code of qgis parameter is available at: qgis/src/core/processing/qgsprocessingparameters.cpp
+  */
+  std::string param_line;
+  for (const std::string& paramKey: appKeyList) {
+    // the following function can throw, but let is thow upper
+    param_line = QGISLineFactory(app, paramKey);
+    if (!param_line.empty())
+      *module_descriptor << param_line << std::endl;
+  }
 
-#if 0
-    	  std::cerr << name;
-    	  std::cerr << " mandatory=" << param->GetMandatory();
-    	  std::cerr << " HasValue=" << param->HasValue();
-    	  std::cerr << " qgis_type=" << qgis_type;
-    	  std::cerr << " optional=" << optional << std::endl;
-#endif
+  // if there is a mandatory output, add a parameter to specify the type of
+  // output pixels
+  if (!mandatory_out_param_name.empty())
+  {
+    *module_descriptor << "*QgsProcessingParameterEnum|outputpixeltype|Output pixel type|uint8;int;float;double|False|2|True" << std::endl;
+  }
+}
 
-    // optional and default value are not in the same order than
-    // other QGis processing parameters for field and band
-    if (type != ParameterType_Field && type != ParameterType_Band)
-    {
-      dFile << "|" << default_value << "|" << optional;
-    }
-    dFile << std::endl;
+
+int main(int argc, char* argv[])
+{
+  // ------- Args parsing --------
+  if (argc < 3)
+  {
+    std::cerr << "Usage : " << argv[0] << " module_list_file OTB_APPLICATION_PATH [out_dir]" << std::endl;
+    return EXIT_FAILURE;
   }
 
-  if (hasRasterOutput)
+  const std::string module_list_path(argv[1]);
+  ApplicationRegistry::AddApplicationPath(argv[2]);
+
+  std::string work_dir("");
+  std::string output_file = module_list_path + ".txt";
+  if (argc > 3)
   {
-    dFile << "*QgsProcessingParameterEnum|outputpixeltype|Output pixel type|uint8;int;float;double|False|2|True" << std::endl;
+    work_dir = std::string(argv[3]) + "/";
   }
+  // ------------------------
+
+  // get the list of all modules to generate their descriptors
+  std::ifstream module_list_file(module_list_path, std::ios_base::in);
+  const std::string algs_txt    = work_dir + "algs.txt";
+
+  // get the algs_txt that contains modules and their groups
+  std::ofstream algs_list;
+  algs_list.open(algs_txt, std::ios::out | std::ios::app);
+
+  std::string module_name;
+
+  // for all modules list, write the detailled QGIS descriptor and add it
+  // in the algs.txt list with its group
+  while (std::getline(module_list_file, module_name)) {
+    bool descriptor_written = false;
+    Application::Pointer appli = ApplicationRegistry::
+                                  CreateApplicationFaster(module_name);
+    assert(!appli.IsNull());
+    const std::string group = appli->GetDocTags().size() > 0 ?
+                              appli->GetDocTags()[0] : "";
+    assert(!group.empty());
+
+    std::string qgis_desc_path = work_dir + module_name + ".txt";
+
+    // write detailled module desc
+    try {
+      writeModuleQGISDescriptor(appli, module_name, group, qgis_desc_path);
+      descriptor_written = true;
+    }
+    catch (const std::runtime_error& e) {
+      std::cerr << "Error while writing " << qgis_desc_path << ": " << e.what()
+                << std::endl;
+    }
 
-  std::cerr << "Writing " << output_file << std::endl;
-  dFile.close();
+    // add it in list
+    if (descriptor_written) {
+      algs_list << group << "|" << module_name << std::endl;
+    }
 
-  std::ofstream indexFile;
-  indexFile.open(algs_txt, std::ios::out | std::ios::app);
-  indexFile << group << "|" << module << std::endl;
-  indexFile.close();
-  std::cerr << "Updated " << algs_txt << std::endl;
+    appli = nullptr;
+  }
 
-  appli = nullptr;
+  algs_list.close();
+  module_list_file.close();
   ApplicationRegistry::CleanRegistry();
 
   return EXIT_SUCCESS;