diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 6c9e9c57d99985cb08325830e8a3b36361697db1..1641dcb5d4aa6b36ddba535e82f643d2becfeae5 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -62,6 +62,10 @@
 extern Ttcn::ExtensionAttributes * parse_extattributes(
   Ttcn::WithAttribPath *w_attrib_path);
 
+// implemented in compiler.y
+extern Common::Value* ttcn3_parse_json_default(
+  const char* p_str, const Common::Location& str_loc);
+
 namespace Common {
   
   map<Type*, void> Type::RecursionTracker::types;
@@ -3168,9 +3172,12 @@ namespace Common {
         }
       }
 
-      if (NULL != jsonattrib->default_value) {
+      if (jsonattrib->default_value.type == JsonAST::JD_STANDARD) {
         chk_json_default();
       }
+      else if (jsonattrib->default_value.type == JsonAST::JD_LEGACY) {
+        chk_json_default_legacy();
+      }
       
       const size_t nof_extensions = jsonattrib->schema_extensions.size();
       if (0 != nof_extensions) {
@@ -3389,9 +3396,33 @@ namespace Common {
     }
   }
   
-  void Type::chk_json_default() 
+  void Type::chk_json_default()
+  {
+    if (jsonattrib->default_value.type != JsonAST::JD_STANDARD || jsonattrib->default_value.str == NULL ||
+        jsonattrib->default_value.loc == NULL) {
+      FATAL_ERROR("Type::chk_json_default");
+    }
+    Error_Context cntxt(this, "In JSON default value");
+    Value* val = ttcn3_parse_json_default(jsonattrib->default_value.str, *jsonattrib->default_value.loc);
+    if (val != NULL) {
+      val->set_my_governor(this);
+      val->set_my_scope(my_scope);
+      val->set_fullname(get_fullname() + ".<JSON_default_value>");
+      val->set_genname(get_genname_own() + "_json_defval");
+      chk_this_value_ref(val);
+      chk_this_value(val, NULL, EXPECTED_CONSTANT, INCOMPLETE_NOT_ALLOWED,
+        OMIT_NOT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT);
+      jsonattrib->default_value.val = val;
+    }
+  }
+  
+  void Type::chk_json_default_legacy() 
   {
-    const char* dval = jsonattrib->default_value;
+    if (jsonattrib->default_value.type != JsonAST::JD_LEGACY || jsonattrib->default_value.str == NULL) {
+      FATAL_ERROR("Type::chk_json_default");
+    }
+    Error_Context cntxt(this, "In JSON default value (legacy)");
+    const char* dval = jsonattrib->default_value.str;
     const size_t dval_len = strlen(dval);
     Type *last = get_type_refd_last();
     bool err = false;
diff --git a/compiler2/Type.hh b/compiler2/Type.hh
index 28c22a85b9777c05df48dc88dcc4937e99233f64..37f2e3cac3a54b780e1a1a8fad082b69a0a3edaf 100644
--- a/compiler2/Type.hh
+++ b/compiler2/Type.hh
@@ -913,6 +913,7 @@ namespace Common {
     
     void chk_json();
     void chk_json_default();
+    void chk_json_default_legacy();
     void chk_json_tag_list();
     /** If the type does not have a jsonattrib, create one. */
     void force_json();
diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc
index ea79ebc3eebd5e15c504b37cd49bfce1623f8090..9e3db1f1087d85d3458e77cb94475867f7afbbb1 100644
--- a/compiler2/Type_codegen.cc
+++ b/compiler2/Type_codegen.cc
@@ -1113,13 +1113,35 @@ void Type::generate_code_jsondescriptor(output_struct *target)
   
   if (NULL == jsonattrib) {
     target->source.global_vars = mputprintf(target->source.global_vars,
-      "const TTCN_JSONdescriptor_t %s_json_ = { FALSE, NULL, FALSE, NULL, "
+      "const TTCN_JSONdescriptor_t %s_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, "
       "FALSE, FALSE, %s, 0, NULL, FALSE, ESCAPE_AS_SHORT };\n"
       , get_genname_own().c_str(), as_map ? "TRUE" : "FALSE");
   } else {
     char* alias = jsonattrib->alias ? mputprintf(NULL, "\"%s\"", jsonattrib->alias) : NULL;
-    char* def_val = jsonattrib->default_value ?
-      mputprintf(NULL, "\"%s\"", jsonattrib->default_value) : NULL;
+    const char* def_type;
+    char* def_val = NULL;
+    switch (jsonattrib->default_value.type) {
+    case JsonAST::JD_UNSET:
+      def_type = "JD_UNSET";
+      break;
+    case JsonAST::JD_LEGACY:
+      def_type = "JD_LEGACY";
+      def_val = mprintf(".str = \"%s\"", jsonattrib->default_value.str);
+      break;
+    case JsonAST::JD_STANDARD:
+      def_type = "JD_STANDARD";
+      Value* v = jsonattrib->default_value.val;
+      const_def cdef;
+      Code::init_cdef(&cdef);
+      generate_code_object(&cdef, v, false);
+      // Generate the initialization of the default values in the post init function
+      // because the module parameters are not initialized in the pre init function
+      target->functions.post_init = v->generate_code_init(target->functions.post_init, v->get_lhs_name().c_str());
+      Code::merge_cdef(target, &cdef);
+      Code::free_cdef(&cdef);
+      def_val = mprintf(".val = &%s", v->get_lhs_name().c_str());
+      break;
+    }
     
     char* enum_texts_name;
     if (0 != jsonattrib->enum_texts.size()) {
@@ -1139,13 +1161,13 @@ void Type::generate_code_jsondescriptor(output_struct *target)
     }
     
     target->source.global_vars = mputprintf(target->source.global_vars,
-      "const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, %s, %s, %s, %s, "
+      "const TTCN_JSONdescriptor_t %s_json_ = { %s, %s, %s, { %s, %s }, %s, %s, %s, "
       "%d, %s, %s, %s };\n"
       , get_genname_own().c_str() 
       , jsonattrib->omit_as_null ? "TRUE" : "FALSE"
       , alias ? alias : "NULL"
       , (jsonattrib->as_value || jsonattrib->tag_list != NULL) ? "TRUE" : "FALSE"
-      , def_val ? def_val : "NULL"
+      , def_type, def_val ? def_val : "NULL"
       , jsonattrib->metainfo_unbound ? "TRUE" : "FALSE"
       , jsonattrib->as_number ? "TRUE" : "FALSE"
       , as_map ? "TRUE" : "FALSE"
@@ -1895,7 +1917,7 @@ void Type::generate_code_Se(output_struct *target)
     if (type->jsonattrib) {
       cur.jsonOmitAsNull = type->jsonattrib->omit_as_null;
       cur.jsonAlias = type->jsonattrib->alias;
-      cur.jsonDefaultValue = type->jsonattrib->default_value;
+      cur.jsonDefaultValue = type->jsonattrib->default_value.str;
       cur.jsonMetainfoUnbound = type->jsonattrib->metainfo_unbound;
       if (type->jsonattrib->tag_list != NULL) {
         rawAST_tag_list* tag_list = type->jsonattrib->tag_list;
@@ -3811,18 +3833,18 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val
   }
   
   // insert default value (if any)
-  if (jsonattrib != NULL && jsonattrib->default_value != NULL) {
+  if (jsonattrib != NULL && jsonattrib->default_value.str != NULL) {
     json.put_next_token(JSON_TOKEN_NAME, "default");
     switch (last->typetype) {
     case T_BOOL:
-      json.put_next_token((jsonattrib->default_value[0] == 't') ?
+      json.put_next_token((jsonattrib->default_value.str[0] == 't') ?
         JSON_TOKEN_LITERAL_TRUE : JSON_TOKEN_LITERAL_FALSE);
       break;
     case T_INT:
     case T_REAL:
-      if (jsonattrib->default_value[0] != 'n' && jsonattrib->default_value[0] != 'i'
-          && jsonattrib->default_value[1] != 'i') {
-        json.put_next_token(JSON_TOKEN_NUMBER, jsonattrib->default_value);
+      if (jsonattrib->default_value.str[0] != 'n' && jsonattrib->default_value.str[0] != 'i'
+          && jsonattrib->default_value.str[1] != 'i') {
+        json.put_next_token(JSON_TOKEN_NUMBER, jsonattrib->default_value.str);
         break;
       }
       // no break, insert the special float values as strings
@@ -3833,7 +3855,7 @@ void Type::generate_json_schema(JSON_Tokenizer& json, bool embedded, bool as_val
     case T_USTR:
     case T_VERDICT:
     case T_ENUM_T: {
-      char* default_str = mprintf("\"%s\"", jsonattrib->default_value);
+      char* default_str = mprintf("\"%s\"", jsonattrib->default_value.str);
       json.put_next_token(JSON_TOKEN_STRING, default_str);
       Free(default_str);
       break; }
diff --git a/compiler2/enum.c b/compiler2/enum.c
index 9a7de6d043b6ec55e1e88bf6f03cc137f123ca71..bfdbfc46c3d0e69c1f7febb42e1b45f085530d41 100644
--- a/compiler2/enum.c
+++ b/compiler2/enum.c
@@ -838,11 +838,16 @@ void defEnumClass(const enum_def *edef, output_struct *output)
       "  size_t value_len = 0;\n"
       "  boolean error = FALSE;\n"
       "  size_t dec_len = 0;\n"
-      "  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();\n"
-      "  if (use_default) {\n"
+      "  boolean use_default = FALSE;\n"
+      "  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
+      "    *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
+      "    return dec_len;\n"
+      "  }\n"
+      "  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {\n"
       // No JSON data in the buffer -> use default value
-      "    value = const_cast<char*>(p_td.json->default_value);\n"
+      "    value = const_cast<char*>(p_td.json->default_value.str);\n"
       "    value_len = strlen(value);\n"
+      "    use_default = TRUE;\n"
       "  } else {\n"
       "    dec_len = p_tok.get_next_token(&token, &value, &value_len);\n"
       "  }\n"
@@ -902,7 +907,7 @@ void defEnumClass(const enum_def *edef, output_struct *output)
       "  }\n"
       "  return (int)dec_len;\n"
       "}\n\n"
-      , name, edef->elements[0].name, enum_type, unknown_value, enum_type
+      , name, name, edef->elements[0].name, enum_type, unknown_value, enum_type
       , unbound_value, unbound_value);
   }
   
diff --git a/compiler2/record.c b/compiler2/record.c
index 50c13528860b413253d74302b7e7cc48bd92e5bd..e544b845e01baa5352f60a4e14e752da6318af39 100644
--- a/compiler2/record.c
+++ b/compiler2/record.c
@@ -3266,10 +3266,13 @@ void gen_xer(const struct_def *sdef, char **pdef, char **psrc)
 char* generate_json_decoder(char* src, const struct_def* sdef)
 {
   src = mputprintf(src,
-    "int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, "
+    "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, "
     "boolean p_silent, boolean p_parent_is_map, int)\n"
-    "{\n", sdef->name,
-    ((sdef->nElements == 1 && !sdef->jsonAsValue) || sdef->jsonAsMapPossible) ? " p_td" : "");
+    "{\n"
+    "  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
+    "    *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
+    "    return 0;\n"
+    "  }\n", sdef->name, sdef->name);
 
   if (sdef->nElements == 1) {
     if (!sdef->jsonAsValue) {
@@ -6897,10 +6900,14 @@ static void defEmptyRecordClass(const struct_def *sdef,
     src = mputprintf(src,
       "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
       "{\n"
-      "  if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {\n"
+      "  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
+      "    *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
+      "    return 0;\n"
+      "  }\n"
+      "  if (p_td.json->default_value.type != JD_UNSET && 0 == p_tok.get_buffer_length()) {\n"
       // use the default value
       "    bound_flag = TRUE;\n"
-      "    return strlen(p_td.json->default_value);\n"
+      "    return strlen(p_td.json->default_value.str);\n"
       "  }\n"
       "  json_token_t token = JSON_TOKEN_NONE;\n"
       "  size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
@@ -6919,7 +6926,7 @@ static void defEmptyRecordClass(const struct_def *sdef,
       "  bound_flag = TRUE;\n\n"
       "  return (int)dec_len;\n"
       "}\n\n"
-      , name);
+      , name, name);
   }
     
   if (oer_needed) {
diff --git a/compiler2/record_of.c b/compiler2/record_of.c
index d762b3eee7587fe5e5f3bf623fadec181fd25ee9..0acad137b6ccb8043f6328186791e7dc5efdfbe0 100644
--- a/compiler2/record_of.c
+++ b/compiler2/record_of.c
@@ -1579,11 +1579,15 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
     src = mputprintf(src,
       "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
       "{\n"
-      "  if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {\n"
+      "  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
+      "    *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
+      "    return 0;\n"
+      "  }\n"
+      "  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {\n"
       // use the default value (currently only the empty array can be set as
       // default value for this type)
       "    set_size(0);\n"
-      "    return strlen(p_td.json->default_value);\n"
+      "    return strlen(p_td.json->default_value.str);\n"
       "  }\n"
       "  json_token_t token = JSON_TOKEN_NONE;\n"
       "  size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
@@ -1653,7 +1657,7 @@ void defRecordOfClass1(const struct_of_def *sdef, output_struct *output)
       "  }\n\n"
       "  return (int)dec_len;\n"
       "}\n\n"
-      , name, type, type, type);
+      , name, name, type, type, type);
   }
   if (oer_needed) {
     // OER encode, RT1
@@ -3105,6 +3109,16 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
     src = mputprintf(src,
       "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)\n"
       "{\n"
+      "  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
+      "    *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
+      "    return 0;\n"
+      "  }\n"
+      "  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {\n"
+      // use the default value (currently only the empty array can be set as
+      // default value for this type)
+      "    set_size(0);\n"
+      "    return strlen(p_td.json->default_value.str);\n"
+      "  }\n"
       "  json_token_t token = JSON_TOKEN_NONE;\n"
       "  size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);\n"
       "  if (JSON_TOKEN_ERROR == token) {\n"
@@ -3167,7 +3181,7 @@ void defRecordOfClassMemAllocOptimized(const struct_of_def *sdef, output_struct
       "  }\n\n"
       "  return (int)dec_len;\n"
       "}\n\n"
-      , name, type);
+      , name, name, type);
   }
   if (oer_needed) {
     // OER encode, RT1, mem. alloc. optimised
diff --git a/compiler2/ttcn3/JsonAST.cc b/compiler2/ttcn3/JsonAST.cc
index af11c51746852eec8a78818c461946e440be3327..2cc49e4770865f2d4492b702fc20cc907dd86006 100644
--- a/compiler2/ttcn3/JsonAST.cc
+++ b/compiler2/ttcn3/JsonAST.cc
@@ -14,6 +14,7 @@
 #include "../../common/memory.h"
 #include <cstddef>
 #include <cstdio>
+#include "../Value.hh"
 
 void JsonSchemaExtension::init(char* p_key, char* p_value)
 {
@@ -38,7 +39,10 @@ void JsonAST::init_JsonAST()
   omit_as_null = false;
   alias = NULL;
   as_value = false;
-  default_value = NULL;
+  default_value.type = JD_UNSET;
+  default_value.str = NULL;
+  default_value.val = NULL;
+  default_value.loc = NULL;
   metainfo_unbound = false;
   as_number = false;
   tag_list = NULL;
@@ -55,7 +59,9 @@ JsonAST::JsonAST(const JsonAST *other_val)
     omit_as_null = other_val->omit_as_null;
     alias = (NULL != other_val->alias) ? mcopystr(other_val->alias) : NULL;
     as_value = other_val->as_value;
-    default_value = (NULL != other_val->default_value) ? mcopystr(other_val->default_value) : NULL;
+    default_value.type = other_val->default_value.type;
+    default_value.str = (NULL != other_val->default_value.str) ? mcopystr(other_val->default_value.str) : NULL;
+    default_value.val = (NULL != other_val->default_value.val) ? other_val->default_value.val->clone() : NULL;
     as_number = other_val->as_number;
     for (size_t i = 0; i < other_val->schema_extensions.size(); ++i) {
       schema_extensions.add(new JsonSchemaExtension(*other_val->schema_extensions[i]));
@@ -75,7 +81,9 @@ JsonAST::JsonAST(const JsonAST *other_val)
 JsonAST::~JsonAST()
 {
   Free(alias);
-  Free(default_value);
+  Free(default_value.str);
+  delete default_value.val;
+  delete default_value.loc;
   for (size_t i = 0; i < schema_extensions.size(); ++i) {
     delete schema_extensions[i];
   }
@@ -93,7 +101,7 @@ JsonAST::~JsonAST()
 boolean JsonAST::empty() const
 {
   return omit_as_null == false && alias == NULL && as_value == false &&
-    default_value == NULL && metainfo_unbound == false && as_number == false &&
+    default_value.type == JD_UNSET && metainfo_unbound == false && as_number == false &&
     tag_list == NULL && as_map == false && enum_texts.size() == 0 &&
     use_null == false && type_indicator != JSON_OBJECT &&
     type_indicator != JSON_LITERAL &&
@@ -167,8 +175,9 @@ void JsonAST::print_JsonAST() const
   if (as_value) {
     printf("Encoding unions as JSON value\n\r");
   }
-  if (default_value) {
-    printf("Default value: %s\n\r", default_value);
+  if (default_value.type != JD_UNSET) {
+    printf("Default value%s: %s\n\r", default_value.type == JD_LEGACY ? " (legacy)" : "",
+      default_value.type == JD_LEGACY ? default_value.str : default_value.val->create_stringRepr().c_str());
   }
   if (as_number) {
     printf("Encoding enumerated values as numbers\n\r");
diff --git a/compiler2/ttcn3/JsonAST.hh b/compiler2/ttcn3/JsonAST.hh
index 800dcdf03828ed185535131892acb5736edcbec2..bfa4f40b68d8add432fdcaa9cdbb57eb6975593d 100644
--- a/compiler2/ttcn3/JsonAST.hh
+++ b/compiler2/ttcn3/JsonAST.hh
@@ -55,6 +55,11 @@ public:
     ESCAPE_AS_USI,
     ESCAPE_AS_TRANSPARENT
   };
+  enum json_default_type {
+    JD_UNSET, // no default value set
+    JD_LEGACY, // legacy default value set through the 'JSON: default' variant attribute
+    JD_STANDARD // standard-compliant default value set through the 'default' variant attribute
+  };
 private:
   void init_JsonAST();
   JsonAST(const JsonAST&);
@@ -63,7 +68,12 @@ public:
   boolean omit_as_null;
   char* alias;
   boolean as_value;
-  char* default_value;
+  struct {
+    json_default_type type;
+    char* str;
+    Common::Value* val;
+    Common::Location* loc;
+  } default_value;
   vector<JsonSchemaExtension> schema_extensions;
   boolean metainfo_unbound;
   boolean as_number;
diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l
index 2f5a31e99cbc54759254fe305aa6a01d6ebcf8ca..baaf0108ecf14c82025a6e804ecf56bbe65101e6 100644
--- a/compiler2/ttcn3/compiler.l
+++ b/compiler2/ttcn3/compiler.l
@@ -197,6 +197,7 @@ LINEMARKER {NUMBER}{WHITESPACE}+\"([^\\\"\r\n]|\\[^\r\n])*\"
 UID [uU][+]?[0-9A-Fa-f]{1,8}
 
 TITAN "$#&&&(#TITANERRONEOUS$#&&^#% "
+TITAN2 "$#&&&(#TITANJSONDEFAULT$#&&^#% "
 
 %x SC_blockcomment SC_cstring
 %x SC_binstring SC_binstring_bad
@@ -246,6 +247,10 @@ TITAN "$#&&&(#TITANERRONEOUS$#&&^#% "
   }
 }
 
+{TITAN2} {
+  RETURN(TitanJsonDefaultHackKeyword);
+}
+
 	/* Eat up comments and whitespaces */
 
 "/*" {
diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y
index 42954a696f6cc14ff9b8733e55d55dbd4a302d73..3b5f2dba79a6e2fa450f688de0c74b012bc42d9f 100644
--- a/compiler2/ttcn3/compiler.y
+++ b/compiler2/ttcn3/compiler.y
@@ -76,11 +76,14 @@ const char *infile = NULL;
 
 static Ttcn::Module *act_ttcn3_module = NULL;
 static Ttcn::ErroneousAttributeSpec *act_ttcn3_erroneous_attr_spec = NULL;
+static Common::Value* act_json_default = NULL;
 bool is_erroneous_parsed = false;
+bool is_json_default_parsed = false;
 static void ttcn3_error(const char *str);
 static Group* act_group = NULL;
 extern string anytype_field(const string& type_name);
 static bool anytype_access = false;
+static bool parsing_error = false;
 
 #ifndef NDEBUG
 
@@ -649,6 +652,7 @@ static const string anyname("anytype");
  * This magic requires the presence of the unused keywords.
  * (It can return an ApplyKeyword if not preceded by a dot) */
 %token TitanErroneousHackKeyword
+%token TitanJsonDefaultHackKeyword
 %token ActionKeyword
 %token ActivateKeyword
 %token AddressKeyword
@@ -2082,11 +2086,12 @@ reduce in case of conflicts.
 GrammarRoot:
   TTCN3Module
   {
-    if (is_erroneous_parsed) {
+    if (is_erroneous_parsed || is_json_default_parsed) {
       delete act_ttcn3_module;
       act_ttcn3_module = NULL;
       Location loc(infile, @1);
-      loc.error("The erroneous attribute cannot be a TTCN-3 module.");
+      loc.error("The %s cannot be a TTCN-3 module.",
+        is_json_default_parsed ? "JSON default value" : "erroneous attribute");
     }
   }
 | TitanErroneousHackKeyword ErroneousAttributeSpec
@@ -2095,7 +2100,29 @@ GrammarRoot:
       delete act_ttcn3_erroneous_attr_spec;
       act_ttcn3_erroneous_attr_spec = NULL;
       Location loc(infile, @$);
-      loc.error("File `%s' does not contain a TTCN-3 module.", infile);
+      if (is_json_default_parsed) {
+        loc.error("JSON default value expected instead of erroneous attribute.");
+      }
+      else {
+        loc.error("File `%s' does not contain a TTCN-3 module.", infile);
+      }
+    }
+  }
+| TitanJsonDefaultHackKeyword Expression
+  {
+    act_json_default = $2;
+    if (!is_json_default_parsed || parsing_error) {
+      delete act_json_default;
+      act_json_default = NULL;
+      if (!is_json_default_parsed) {
+        Location loc(infile, @2);
+        if (is_erroneous_parsed) {
+          loc.error("Erroneous attribute expected instead of JSON default value.");
+        }
+        else {
+          loc.error("File `%s' does not contain a TTCN-3 module.", infile);
+        }
+      }
     }
   }
 | error
@@ -11431,6 +11458,7 @@ static void ttcn3_error(const char *str)
     // the most recently parsed token is unknown
     loc.error("%s", str);
   }
+  parsing_error = true;
 }
 
 int ttcn3_parse_file(const char* filename, boolean generate_code)
@@ -11448,6 +11476,7 @@ int ttcn3_parse_file(const char* filename, boolean generate_code)
   init_ttcn3_lex();
 
   is_erroneous_parsed = false;
+  is_json_default_parsed = false;
   NOTIFY("Parsing TTCN-3 module `%s'...", filename);
 
   int retval = ttcn3_parse();
@@ -11471,6 +11500,7 @@ Ttcn::ErroneousAttributeSpec* ttcn3_parse_erroneous_attr_spec_string(
   const char* p_str, const Common::Location& str_loc)
 {
   is_erroneous_parsed = true;
+  is_json_default_parsed = false;
   act_ttcn3_erroneous_attr_spec = NULL;
   string titan_err_str("$#&&&(#TITANERRONEOUS$#&&^#% ");
   size_t hack_str_len = titan_err_str.size();
@@ -11490,6 +11520,30 @@ Ttcn::ErroneousAttributeSpec* ttcn3_parse_erroneous_attr_spec_string(
   return act_ttcn3_erroneous_attr_spec;
 }
 
+Common::Value* ttcn3_parse_json_default(
+  const char* p_str, const Common::Location& str_loc)
+{
+  is_erroneous_parsed = false;
+  is_json_default_parsed = true;
+  act_json_default = NULL;
+  string titan_err_str("$#&&&(#TITANJSONDEFAULT$#&&^#% ");
+  size_t hack_str_len = titan_err_str.size();
+  string *parsed_string = parse_charstring_value(p_str, str_loc);
+  titan_err_str += *parsed_string;
+  delete parsed_string;
+  init_erroneous_lex(str_loc.get_filename(), str_loc.get_first_line(), str_loc.get_first_column()-hack_str_len+1);
+  yy_buffer_state *flex_buffer = ttcn3__scan_string(titan_err_str.c_str());
+  if (flex_buffer == NULL) {
+    ERROR("Flex buffer creation failed.");
+    return NULL;
+  }
+  yyparse();
+  ttcn3_lex_destroy();
+  free_dot_flag_stuff();
+
+  return act_json_default;
+}
+
 #ifndef NDEBUG
 static void yyprint(FILE *file, int type, const YYSTYPE& value)
 {
diff --git a/compiler2/ttcn3/rawAST.l b/compiler2/ttcn3/rawAST.l
index 53aa0a9c70e909e8bdea41ab2b7238f8e95fff61..9626290b73a198e497d17f7983fb0e8fc9586494 100644
--- a/compiler2/ttcn3/rawAST.l
+++ b/compiler2/ttcn3/rawAST.l
@@ -491,7 +491,7 @@ literal       RETURN(XKWliteral);
   else yylval.str = mcopystr(yytext);
   RETURN(XJsonValueSegment);
 }
-[)]           { BEGIN(jsoncodec); RETURN(XJsonValueEnd); }
+[)]           { BEGIN(INITIAL); RETURN(XJsonValueEnd); }
 [\"][\"]      { yylval.str = mcopystr("\\\""); RETURN(XJsonValueSegment); }
 [^\"\\)]+     { yylval.str = mcopystr(yytext); RETURN(XJsonValueSegment); }
 }
diff --git a/compiler2/ttcn3/rawAST.y b/compiler2/ttcn3/rawAST.y
index 9a6f94f67391142a9944efb1a03eaa69fc0e4cac..be97c03aac40a706d21abf72cda4e67ac83affb7 100644
--- a/compiler2/ttcn3/rawAST.y
+++ b/compiler2/ttcn3/rawAST.y
@@ -1860,7 +1860,8 @@ XAsValue:
 ;
 
 XDefault:
-  XKWdefault XOptSpaces XJsonValue { jsonstruct->default_value = $3; }
+  XKWdefault XOptSpaces XJsonValue
+  { jsonstruct->default_value.str = $3; jsonstruct->default_value.type = JsonAST::JD_LEGACY; }
 ;
 
 XExtend:
@@ -1938,7 +1939,12 @@ JAsValue:
 ;
 
 JDefault:
-  XKWdefault XOptSpaces XJsonValue XOptSpaces { jsonstruct->default_value = $3; } 
+  XKWdefault XOptSpaces XJsonValue XOptSpaces
+  {
+    jsonstruct->default_value.str = $3;
+    jsonstruct->default_value.type = JsonAST::JD_STANDARD;
+    jsonstruct->default_value.loc = new Common::Location(infile, @3);
+  }
 ;
 
 JExtend:
diff --git a/compiler2/union.c b/compiler2/union.c
index dfcc4230ad2ef3983806ffcf32b14d8c6b39b0c6..253a99ff524fe2774e44360a44789d58e32dbf98 100644
--- a/compiler2/union.c
+++ b/compiler2/union.c
@@ -2195,10 +2195,10 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
     
     // JSON decode
     src = mputprintf(src,
-      "int %s::JSON_decode(const TTCN_Typedescriptor_t&%s, JSON_Tokenizer& p_tok, "
+      "int %s::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, "
       "boolean p_silent, boolean, int p_chosen_field)\n"
       "{\n"
-      , name, sdef->nElements > 0 && !sdef->jsonAsValue ? " p_td" : "");
+      , name);
     if (sdef->nElements > 0) {
       src = mputprintf(src,
         "  if (0 <= p_chosen_field && %d > p_chosen_field) {\n"
@@ -2211,10 +2211,14 @@ void defUnionClass(struct_def const *sdef, output_struct *output)
           , (int)i, at_field, sdef->elements[i].name
           , sdef->elements[i].typedescrname);
       }
-      src = mputstr(src, 
+      src = mputprintf(src, 
         "    }\n"
         "  }\n"
-        "  json_token_t j_token = JSON_TOKEN_NONE;\n");
+        "  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {\n"
+        "    *this = *static_cast<const %s*>(p_td.json->default_value.val);\n"
+        "    return 0;\n"
+        "  }\n"
+        "  json_token_t j_token = JSON_TOKEN_NONE;\n", name);
       if (!sdef->jsonAsValue) {
         src = mputstr(src,
           " if (p_td.json->as_value) {\n");
diff --git a/core/Bitstring.cc b/core/Bitstring.cc
index 28e6d0b84e1b8eafea2e7ec8cd33e26f85d8b3ab..1742382f8265da4e49ad46d59c512cf5f4d86ee0 100644
--- a/core/Bitstring.cc
+++ b/core/Bitstring.cc
@@ -1204,11 +1204,16 @@ int BITSTRING::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_
   size_t value_len = 0;
   boolean error = FALSE;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const BITSTRING*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/Boolean.cc b/core/Boolean.cc
index 5000c616d556f686310cd63fb02349680833631b..cdae579c4e7aeee8c1096738f8f7ee02f8a07ff5 100644
--- a/core/Boolean.cc
+++ b/core/Boolean.cc
@@ -770,9 +770,13 @@ int BOOLEAN::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_to
 {
   json_token_t token = JSON_TOKEN_NONE;
   size_t dec_len = 0;
-  if (p_td.json->default_value && 0 == p_tok.get_buffer_length()) {
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const BOOLEAN*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    if (strcmp(p_td.json->default_value, "true") == 0) {
+    if (strcmp(p_td.json->default_value.str, "true") == 0) {
       token = JSON_TOKEN_LITERAL_TRUE;
     } 
     else {
diff --git a/core/Charstring.cc b/core/Charstring.cc
index 6efe3f955f6c9b313b0df4ddca3c2e7b77cba632..a59e253b826bdc767bb7e5263c0a3589b9443d64 100644
--- a/core/Charstring.cc
+++ b/core/Charstring.cc
@@ -1836,11 +1836,16 @@ int CHARSTRING::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p
   char* value = 0;
   size_t value_len = 0;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const CHARSTRING*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/Float.cc b/core/Float.cc
index 8b48d90f851508c0c4fddc8ada01582a6568d324..5546d1fc07746d7cf717eb58157314470abcb4d6 100644
--- a/core/Float.cc
+++ b/core/Float.cc
@@ -1135,11 +1135,16 @@ int FLOAT::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok,
   char* value = 0;
   size_t value_len = 0;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const FLOAT*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/Hexstring.cc b/core/Hexstring.cc
index 35799bc1447f3ca1fff2a42ce743223393c6a0af..a4a25d9614db19cff2ea0dc36591284c490df796 100644
--- a/core/Hexstring.cc
+++ b/core/Hexstring.cc
@@ -1082,11 +1082,16 @@ int HEXSTRING::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_
   size_t value_len = 0;
   boolean error = FALSE;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const HEXSTRING*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/Integer.cc b/core/Integer.cc
index 1f8d774179042f099750a2363cee7b0dc8f83210..18064b080894313b762279f45f881a01347ea7ad 100644
--- a/core/Integer.cc
+++ b/core/Integer.cc
@@ -1759,11 +1759,16 @@ int INTEGER::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_to
   char* value = 0;
   size_t value_len = 0;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const INTEGER*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/JSON.cc b/core/JSON.cc
index 835877a3d7a71a2cb002cb4e4faeddbaf2b1a702..e1f285259835a195218dfb36fbfe3b6b192eea12 100644
--- a/core/JSON.cc
+++ b/core/JSON.cc
@@ -32,55 +32,55 @@
 #include <sys/types.h>
 
 // JSON descriptors for base types
-const TTCN_JSONdescriptor_t INTEGER_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t INTEGER_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t FLOAT_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t FLOAT_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t BOOLEAN_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t BOOLEAN_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t BITSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t BITSTRING_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t HEXSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t HEXSTRING_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t OCTETSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t OCTETSTRING_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t CHARSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t CHARSTRING_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t UNIVERSAL_CHARSTRING_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t UNIVERSAL_CHARSTRING_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t VERDICTTYPE_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t VERDICTTYPE_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t GeneralString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t GeneralString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t NumericString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t NumericString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t UTF8String_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t UTF8String_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t PrintableString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t PrintableString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t UniversalString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t UniversalString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t BMPString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t BMPString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t GraphicString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t GraphicString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t IA5String_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t IA5String_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t TeletexString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t TeletexString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t VideotexString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t VideotexString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t VisibleString_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t VisibleString_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t ASN_NULL_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t ASN_NULL_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t OBJID_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t OBJID_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t ASN_ROID_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t ASN_ROID_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t ASN_ANY_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t ASN_ANY_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
-const TTCN_JSONdescriptor_t ENUMERATED_json_ = { FALSE, NULL, FALSE, NULL, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
+const TTCN_JSONdescriptor_t ENUMERATED_json_ = { FALSE, NULL, FALSE, { JD_UNSET, NULL }, FALSE, FALSE, FALSE, 0, NULL, FALSE, ESCAPE_AS_SHORT };
 
 
 
@@ -1515,4 +1515,4 @@ void bson2json_coding(TTCN_Buffer& buff, JSON_Tokenizer& tok, bool in_object, bo
         TTCN_error("Unexpected type %i while decoding using bson2json().", *type);
     }
   }
-}
\ No newline at end of file
+}
diff --git a/core/JSON.hh b/core/JSON.hh
index 0bc1baba53a2fd5b1f369c58638659c422c7363c..4e26c178ab176d9617a76ba0603d5a01e8e76fa6 100644
--- a/core/JSON.hh
+++ b/core/JSON.hh
@@ -20,6 +20,7 @@ class TTCN_Buffer;
 class JSON_Tokenizer;
 class CHARSTRING;
 class INTEGER;
+class Base_Type;
 
 /** Enumerated text change structure */
 struct JsonEnumText {
@@ -34,6 +35,12 @@ enum json_string_escaping {
   ESCAPE_AS_TRANSPARENT /* do not escape anything, except control characters */
 };
 
+enum json_default_type {
+  JD_UNSET, // no default value set
+  JD_LEGACY, // legacy default value set through the 'JSON: default' variant attribute
+  JD_STANDARD // standard-compliant default value set through the 'default' variant attribute
+};
+
 /** Descriptor for JSON encoding/decoding during runtime */
 struct TTCN_JSONdescriptor_t 
 {
@@ -58,8 +65,14 @@ struct TTCN_JSONdescriptor_t
   boolean as_value;
   
   /** Decoding only.
-    * Fields that don't appear in the JSON code will decode this value instead. */
-  const char* default_value;
+    * Fields may have a default value set in case they don't appear in the JSON code. */
+  struct {
+    json_default_type type; /// indicates whether this field has a default value, and which type
+    union {
+      const char* str; /// legacy default value - contains a JSON value, it is decoded and assigned to this field
+      const Base_Type* val; /// standard-compliant default value - it is assigned to the field, no decoding needed
+    };
+  } default_value;
   
   /** If set, encodes unbound fields of records and sets as null and inserts a
     * meta info field into the JSON object specifying that the field is unbound.
diff --git a/core/Objid.cc b/core/Objid.cc
index dff4ad30f7714ffdf7bb6c12a35fef593a9b63a8..83947933a273093980f5d200ce9f702f1ab69488 100644
--- a/core/Objid.cc
+++ b/core/Objid.cc
@@ -638,11 +638,16 @@ int OBJID::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok,
   size_t value_len = 0;
   boolean error = FALSE;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const OBJID*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/Octetstring.cc b/core/Octetstring.cc
index f4ef7e14296cb18a63de998896e8af99dc338874..59f1e54a268e83f5aa1b3768a84193c9451225bf 100644
--- a/core/Octetstring.cc
+++ b/core/Octetstring.cc
@@ -1336,11 +1336,16 @@ int OCTETSTRING::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
   size_t value_len = 0;
   boolean error = FALSE;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const OCTETSTRING*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/Universal_charstring.cc b/core/Universal_charstring.cc
index 2d64f115008351c82192e9039431b241ee415a08..cff22da750ba4b38e08be62b7f076887107b094b 100644
--- a/core/Universal_charstring.cc
+++ b/core/Universal_charstring.cc
@@ -2596,11 +2596,16 @@ int UNIVERSAL_CHARSTRING::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_To
   char* value = 0;
   size_t value_len = 0;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const UNIVERSAL_CHARSTRING*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core/Verdicttype.cc b/core/Verdicttype.cc
index 6524f39752279a9f0ceaaed83f822e00e690533f..b7f5623ce2608edb4cd031f2f3b4eb55ca9b6b5c 100644
--- a/core/Verdicttype.cc
+++ b/core/Verdicttype.cc
@@ -396,11 +396,16 @@ int VERDICTTYPE::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
   char* value = 0;
   size_t value_len = 0;
   size_t dec_len = 0;
-  boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
-  if (use_default) {
+  boolean use_default = FALSE;
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    *this = *static_cast<const VERDICTTYPE*>(p_td.json->default_value.val);
+    return dec_len;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // No JSON data in the buffer -> use default value
-    value = const_cast<char*>(p_td.json->default_value);
+    value = const_cast<char*>(p_td.json->default_value.str);
     value_len = strlen(value);
+    use_default = TRUE;
   } else {
     dec_len = p_tok.get_next_token(&token, &value, &value_len);
   }
diff --git a/core2/Basetype2.cc b/core2/Basetype2.cc
index 48c5ff62150614a9a21c0a91099707c5343da9ed..c80ad6051c76b813ca8eff09dcb9cc030377aeb5 100644
--- a/core2/Basetype2.cc
+++ b/core2/Basetype2.cc
@@ -1603,11 +1603,15 @@ int Record_Of_Type::JSON_encode_negtest(const Erroneous_descriptor_t* p_err_desc
 int Record_Of_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok,
                                 boolean p_silent, boolean, int)
 {
-  if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    set_value(p_td.json->default_value.val);
+    return 0;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // use the default value (currently only the empty array can be set as
     // default value for this type)
     set_size(0);
-    return strlen(p_td.json->default_value);
+    return strlen(p_td.json->default_value.str);
   }
   json_token_t token = JSON_TOKEN_NONE;
   size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);
@@ -6191,6 +6195,10 @@ int Record_Type::JSON_encode_negtest(const Erroneous_descriptor_t* p_err_descr,
 int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok,
                              boolean p_silent, boolean p_parent_is_map, int)
 {
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    set_value(p_td.json->default_value.val);
+    return 0;
+  }
   if (p_td.json->as_value) {
     if (get_at(0)->is_optional()) {
       // can only happen if the record has the 'JSON:object' attribute;
@@ -6391,7 +6399,7 @@ int Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer&
         (int)strlen(fld_name(field_idx)), fld_name(field_idx));
     }
     else if (!field_found[field_idx]) {
-      if (NULL != fld_descr(field_idx)->json && NULL != fld_descr(field_idx)->json->default_value) {
+      if (NULL != fld_descr(field_idx)->json && fld_descr(field_idx)->json->default_value.type != JD_UNSET) {
         get_at(field_idx)->JSON_decode(*fld_descr(field_idx), DUMMY_BUFFER, p_silent, FALSE);
       }
       else if (field->is_optional()) {
@@ -7580,10 +7588,14 @@ int Empty_Record_Type::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer&
 
 int Empty_Record_Type::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent, boolean, int)
 {
-  if (NULL != p_td.json->default_value && 0 == p_tok.get_buffer_length()) {
+  if (p_td.json->default_value.type == JD_STANDARD && 0 == p_tok.get_buffer_length()) {
+    set_value(p_td.json->default_value.val);
+    return 0;
+  }
+  if (p_td.json->default_value.type == JD_LEGACY && 0 == p_tok.get_buffer_length()) {
     // use the default value
     bound_flag = TRUE;
-    return strlen(p_td.json->default_value);
+    return strlen(p_td.json->default_value.str);
   }
   json_token_t token = JSON_TOKEN_NONE;
   size_t dec_len = p_tok.get_next_token(&token, NULL, NULL);
diff --git a/regression_test/EncodeDecode/JSON/JsonComplexTest/AttributeTestcases.ttcn b/regression_test/EncodeDecode/JSON/JsonComplexTest/AttributeTestcases.ttcn
index 26f3718e21c197a12785b43e40b4a5ee960187b7..f7f263a0ca2cdd899b4163894e6623f896f199dc 100644
--- a/regression_test/EncodeDecode/JSON/JsonComplexTest/AttributeTestcases.ttcn
+++ b/regression_test/EncodeDecode/JSON/JsonComplexTest/AttributeTestcases.ttcn
@@ -185,8 +185,8 @@ testcase tc_attribute_as_value() runs on CT {
   setverdict(pass);
 }
 
-// Testing default values for record fields (decoding only)
-testcase tc_attribute_default() runs on CT {
+// Testing legacy default values for record fields (decoding only)
+testcase tc_attribute_default_legacy() runs on CT {
   var octetstring os := char2oct("{}");
   var RecDef d := { i := -19, f := 1000000.000000, b := false, bs := '101'B, hs := 'DEAD'H, os := '1DE7'O, cs := "empty", ucs := "üres", size := Tiny, vt := fail };
   f_bool2verdict( match(f_dec_def(os), d) );
@@ -196,6 +196,43 @@ testcase tc_attribute_default() runs on CT {
   f_bool2verdict( match(f_dec_def(os), d) );
 }
 
+// Testing standard-compliant default values for record fields of basic types (decoding only)
+testcase tc_attribute_default_basic() runs on CT {
+  var octetstring os := char2oct("{}");
+  var RecDef2 d := { i := -19, f := 1000000.000000, b := false, bs := '101'B, hs := 'DEAD'H, os := '1DE7'O, cs := "empty", ucs := "üres", size := Tiny, vt := fail };
+  f_bool2verdict( match(f_dec_def2(os), d) );
+
+  os := char2oct("{ \"b\" : null }");
+  d.b := omit;
+  f_bool2verdict( match(f_dec_def2(os), d) );
+}
+
+// Tests for standard-compliant default values taken from the TTCN-3 standard change request CR 7968 v5 (decoding only)
+testcase tc_attribute_default_standard() runs on CT {
+  var octetstring os := char2oct("{ \"name\" : \"Shoe\", \"price\" : 29.50, \"text\" : \"available\" }");
+  var Product2 p := { name := "Shoe", price := 29.500000, id := 'FFFF'O, origin := "Hungary", text := "available" };
+  f_bool2verdict( match(f_dec_prod2(os), p) );
+  
+  os := char2oct("{ \"name\" : \"Shirt\", \"price\" : 12.99, \"id\" : null }");
+  p := { name := "Shirt", price := 12.990000, id := omit, origin := "Hungary", text := char(1, 2, 3, 4) & char(5, 6, 7, 8) & "?" };
+  f_bool2verdict( match(f_dec_prod2(os), p) );
+  
+  os := char2oct("{ \"name\" : \"test shopper\" }");
+  var Shopping_cart sc := { name := "test shopper", product := { name := "Shirt", price := 12.990000, id := omit, origin := "Hungary", text := "available" } };
+  f_bool2verdict( match(f_dec_cart(os), sc) );
+  
+  os := char2oct("{ \"name\" : \"test shopper\" }");
+  var Shopping_cart_2 sc2 := { name := "test shopper", product := { name := "Size \"M\" Shirt", price := 12.990000, id := omit, origin := "Hungary", text := "available" } };
+  f_bool2verdict( match(f_dec_cart2(os), sc2) );
+}
+
+// Testing standard-compliant default values for record fields of structured types (decoding only)
+testcase tc_attribute_default_structured() runs on CT {
+  var octetstring os := char2oct("{ }");
+  var RecDef3 d := { er := { }, u := { i := -6 }, roi := { 1, 2, 3 } };
+  f_bool2verdict( match(f_dec_def3(os), d) );
+}
+
 // Encoding a few values of ASN.1 types with the coding instruction "as value"
 // Results are the same as with the TTCN-3 types
 testcase tc_attribute_as_value_asn() runs on CT {
@@ -746,7 +783,10 @@ control {
   execute(tc_attribute_prettyprint2());
   execute(tc_attribute_union());
   execute(tc_attribute_as_value());
-  execute(tc_attribute_default());
+  execute(tc_attribute_default_legacy());
+  execute(tc_attribute_default_basic());
+  execute(tc_attribute_default_standard());
+  execute(tc_attribute_default_structured());
   execute(tc_attribute_as_value_asn());
   execute(tc_attribute_optional_as_value());
   execute(tc_attribute_metainfo_for_unbound());
diff --git a/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonFunctions.ttcn b/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonFunctions.ttcn
index d9bdb7c454887a0adc1f6b4d53293db3ac0405d3..2dd3df6c2a33de4836e53eaa147c10988eeb345b 100644
--- a/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonFunctions.ttcn
+++ b/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonFunctions.ttcn
@@ -322,6 +322,21 @@ external function f_dec_stuff(in octetstring x) return Stuff
 external function f_dec_def(in octetstring x) return RecDef
   with { extension "prototype(convert) decode(JSON)" }
 
+external function f_dec_def2(in octetstring x) return RecDef2
+  with { extension "prototype(convert) decode(JSON)" }
+
+external function f_dec_prod2(in octetstring x) return Product2
+  with { extension "prototype(convert) decode(JSON)" }
+
+external function f_dec_cart(in octetstring x) return Shopping_cart
+  with { extension "prototype(convert) decode(JSON)" }
+
+external function f_dec_cart2(in octetstring x) return Shopping_cart_2
+  with { extension "prototype(convert) decode(JSON)" }
+
+external function f_dec_def3(in octetstring x) return RecDef3
+  with { extension "prototype(convert) decode(JSON)" }
+
 external function f_dec_hpt(in octetstring x) return HasPardType
   with { extension "prototype(convert) decode(JSON)" }
 
diff --git a/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonTypes1.ttcn b/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonTypes1.ttcn
index 518a2c821ffe68210a8148a264db7ff2a5ae995c..10297fc4d2d6503214bb386462ce294e8417f83b 100644
--- a/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonTypes1.ttcn
+++ b/regression_test/EncodeDecode/JSON/JsonComplexTest/JsonTypes1.ttcn
@@ -188,6 +188,81 @@ type record RecDef {
   variant(b) "JSON:default(false)";
 }
 
+type record RecDef2 {
+  integer i,
+  float f,
+  boolean b optional,
+  bitstring bs,
+  hexstring hs,
+  octetstring os,
+  charstring cs,
+  universal charstring ucs,
+  enumerated { Tiny, Small, Medium, Large, Huge } size,
+  verdicttype vt
+} with {
+  variant(cs) "default(\"empty\")";
+  variant(i) "default(-19)";
+  variant(f) "default(1.0e6)";
+  variant(size) "default(Tiny)";
+  variant(os) "default('1DE7'O)";
+  variant(ucs) "default(""üres"")";
+  variant(bs) "default ('101'B)";
+  variant(hs) "default('DEAD'H)";
+  variant(vt) "default(fail)";
+  variant(b) "default(false)";
+}
+
+type record Product2 {
+	charstring name,
+	float price,
+	octetstring id optional,
+	charstring origin,
+	universal charstring text
+}
+with {
+	variant(id) "default ('FFFF'O)"
+	variant(origin) "default(""Hungary"")"
+	variant(text) "default (char(1,2,3,4\) & char(5,6,7,8\) & ""?"")"
+}
+
+type record Shopping_cart {
+	charstring name,
+	Product2 product
+} with {
+	variant(product) "default ({""Shirt"", 12.99, omit, ""Hungary"", ""available"" })"
+}
+
+const Product2 c_defaultProduct := {	
+	name := "Size ""M"" Shirt",
+	price := 12.99,
+	id := omit,
+	origin := "Hungary",
+	text := "available"
+}
+
+type record Shopping_cart_2 {
+	charstring name,
+	Product2 product
+} with {
+	variant(product) "default (c_defaultProduct)"
+}
+
+type union Uni {
+  integer i,
+  charstring cs
+}
+
+type record RecDef3 {
+  EmptyRec er,
+  Uni u,
+  RoI roi
+}
+with {
+  variant (er) "default ( { } )";
+  variant (u) "default ({ i := -6 })";
+  variant (roi) "default ({1,2,3})";
+}
+
 type record HasPardType {
   ProtocolElem_Field1 pard,
   boolean buul,