<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Answers to: Can not persist Business Data to Repo after changing data type</title><link>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type</link><description>&lt;p&gt;Hi all&lt;/p&gt;
&lt;p&gt;I'm using Ivy 6.3 and use ivy.repo api to persist data. When i persits data as this JSON:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;"qualificationMessageResults": [
        {
            "code": "amount",
            "severity": "ORANGE",
            "message": {
                "descriptor": {
                    "content": "/ch/axonivy/fintech/soba/Message/PreQualification/Amount/amountBetweenMinAmountAndMaxAmountForReplacement",
                    "type": "URI"
                },
                "paramDescriptors": [
                    {
                        "descriptor": {
                            "content": "500000",
                            "type": "PLAIN_TEXT",
                            "placeHolder": "{minAmount}"
                        },
                        "paramDescriptors": []
                    }
                ]
            }
        }
    ]
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The api say:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; [errorId=15BCE2ED377AD1E0, request=HTTP POST ch/axonivy/fintech/soba/showcase/DemoSobaPersistence/DemoSobaPersistenceProcess.mod/15A1694DAA1C0A9F(9907.9907.17.0), session=1, task=9907, application=102, requestId=4093, executionContext=1, pmv=Portal$soba_test$2, hd=ch.axonivy.fintech.soba.showcase.DemoSobaPersistence, processElement=15A168DC648B6158-f9]
Caused by: ch.ivyteam.ivy.persistence.PersistencyException: Could not create BusinessData.
    at ch.ivyteam.ivy.business.data.store.internal.ElasticSystemDbPersistence.execute(ElasticSystemDbPersistence.java:115)
    at ch.ivyteam.ivy.business.data.store.internal.ElasticSystemDbPersistence.execute(ElasticSystemDbPersistence.java:104)
    at ch.ivyteam.ivy.business.data.store.internal.ElasticSystemDbPersistence.create(ElasticSystemDbPersistence.java:89)
    at ch.ivyteam.ivy.business.data.store.internal.BusinessDataRepositoryImpl.persist(BusinessDataRepositoryImpl.java:112)
    at ch.ivyteam.ivy.business.data.store.internal.BusinessDataRepositoryImpl.save(BusinessDataRepositoryImpl.java:96)
    at ch.axonivy.fintech.standard.dossier.persistence.BaseDossierPersistence.persist(BaseDossierPersistence.java:35)
    at ch.axonivy.fintech.soba.dossier.service.SobaDossierService.persist(SobaDossierService.java:155)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at ch.ivyteam.ivy.scripting.internal.types.IvyJavaMethod.invokeImpl(IvyJavaMethod.java:73)
    ... 208 more
[errorId=15BCE2ED377AD1E0, request=HTTP POST ch/axonivy/fintech/soba/showcase/DemoSobaPersistence/DemoSobaPersistenceProcess.mod/15A1694DAA1C0A9F(9907.9907.17.0), session=1, task=9907, application=102, requestId=4093, executionContext=1, pmv=Portal$soba_test$2, hd=ch.axonivy.fintech.soba.showcase.DemoSobaPersistence, processElement=15A168DC648B6158-f9]
Caused by: ch.ivyteam.ivy.business.data.store.search.internal.elasticsearch.ElasticsearchException: Elasticsearch update index of document failed because of: {"root_cause":[{"type":"mapper_parsing_exception","reason":"failed to parse [onlineMortgageProgress.qualificationMessageResults.message]"}],"type":"mapper_parsing_exception","reason":"failed to parse [onlineMortgageProgress.qualificationMessageResults.message]","caused_by":{"type":"illegal_argument_exception","reason":"unknown property [descriptor]"}}
    at ch.ivyteam.ivy.business.data.store.search.internal.elasticsearch.JestOperation.checkStatusAndThrow(JestOperation.java:61)
    at ch.ivyteam.ivy.business.data.store.search.internal.elasticsearch.JestOperation.execute(JestOperation.java:39)
    at ch.ivyteam.ivy.business.data.store.search.internal.elasticsearch.JestIndexSynchronizer.execute(JestIndexSynchronizer.java:165)
    at ch.ivyteam.ivy.business.data.store.search.internal.elasticsearch.JestIndexSynchronizer.updateIndex(JestIndexSynchronizer.java:64)
    at ch.ivyteam.ivy.business.data.store.search.internal.ElasticBusinessDataSearchIndex.update(ElasticBusinessDataSearchIndex.java:30)
    at ch.ivyteam.ivy.business.data.store.internal.ElasticSystemDbPersistence.lambda$1(ElasticSystemDbPersistence.java:96)
    at ch.ivyteam.ivy.persistence.base.AbstractPersistencyService.execute(AbstractPersistencyService.java:177)
    at ch.ivyteam.ivy.persistence.base.AbstractPersistencyService.execute(AbstractPersistencyService.java:240)
    at ch.ivyteam.ivy.persistence.base.ClassPersistencyService.execute(ClassPersistencyService.java:694)
    at
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My object QualificationMessageResult has list of Object A, and object A has two properties: a object &lt;strong&gt;descriptor&lt;/strong&gt; and a list of Object A (looped Object) with name: &lt;strong&gt;paramDescriptors&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Can anyone suggest me something?&lt;/p&gt;
&lt;p&gt;Thanks&lt;/p&gt;</description><atom:link href="https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type" rel="self"></atom:link><language>en</language><lastBuildDate>Tue, 04 Jul 2017 08:50:20 -0400</lastBuildDate><item><title>Comment by Reguel Wermelinger on Reguel Wermelinger's answer</title><link>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type#2732</link><description>&lt;p&gt;This demo is just for illustrative purposes. In a real world scenario you should pay special care that the serializer / deserializer implementation is rock solid. For simple demonstration I've just used a simple field separator here...&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Reguel Wermelinger</dc:creator><pubDate>Tue, 04 Jul 2017 08:50:20 -0400</pubDate><guid>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type#2732</guid></item><item><title>Answer by Reguel Wermelinger</title><link>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type/2731</link><description>&lt;p&gt;You do not run into this problem if you &lt;strong&gt;just introduce a new attribute for the new type&lt;/strong&gt; instead of re-using the existing attribute that already contains other data. Business Data is explicitly designed to allow simple data migration. So it does not throw any errors for unknown fields.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;However, there is a work around&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you just wrapped the String in a complex object you could work around the problem by influencing the JSON serialization. With Jackson you could for instance store the new complex object also as string and read it back to a complex object. And of course this also allows you to handle legacy serialized objects.&lt;/p&gt;
&lt;p&gt;The rough concept is described here: &lt;a href="http://developer.axonivy.com/doc/latest/DesignerGuideHtml/ivy.datamodeling.html#ivy.businessdata.serialization.module"&gt;http://developer.axonivy.com/doc/latest/DesignerGuideHtml/ivy.datamodeling.html#ivy.businessdata.serialization.module&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A sample implementation could do the following. Here we serialize a complex Person object as a raw String.&lt;/p&gt;
&lt;p&gt;FIRST: Write your own serializer module:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.axonivy;

import java.io.IOException;

import org.apache.commons.lang3.StringUtils;

import ch.ivyteam.ivy.environment.Ivy;

import com.axonivy.sample.Person;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;

public class CustomBusinessDataModule extends SimpleModule {

    private static final long serialVersionUID = 1L;
    private static final String SEPARATOR = "|";

    public CustomBusinessDataModule()
    {
        Ivy.log().info("registered custom module!");
        addSerializer(Person.class, new CustomPersonSerializer());
        addDeserializer(Person.class, new CustomPersonDeSerializer());
    }

    @SuppressWarnings("serial")
    private static class CustomPersonSerializer extends StdScalarSerializer&amp;lt;Person&amp;gt;
    {

        public CustomPersonSerializer() {
            super(Person.class);
        }

        @Override
        public void serialize(Person value, JsonGenerator gen,
                SerializerProvider provider) throws IOException {
            gen.writeString(value.getFirstname()+SEPARATOR+value.getLastname());
        }
    }

    @SuppressWarnings("serial")
    private static class CustomPersonDeSerializer extends StdScalarDeserializer&amp;lt;Person&amp;gt;
    {
        public CustomPersonDeSerializer()
        {
            super(Person.class);
        }

        @Override
        public Person deserialize(JsonParser p, DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            String value = p.readValueAs(String.class);
            if (!StringUtils.contains(value, SEPARATOR))
            {
                // old version.... -&amp;gt; take special care!
                return new Person();
            }

            String[] parts = StringUtils.split(value, SEPARATOR);
            Person person = new Person();
            person.setFirstname(parts[0]);
            person.setLastname(parts[1]);
            return person;
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SECOND: register it via service SPI: &lt;/p&gt;
&lt;p&gt;&lt;img alt="alt text" src="http://answers.axonivy.com/upfiles/registerCustomJacksonModule.png"&gt;&lt;/p&gt;
&lt;p&gt;Here you see the custom serializer in action:&lt;/p&gt;
&lt;p&gt;&lt;a href="/upfiles/businessDataSerializer_66.iar"&gt;businessDataSerializer_66.iar&lt;/a&gt;
&lt;img alt="alt text" src="http://answers.axonivy.com/upfiles/customCreatedJson.png"&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Reguel Wermelinger</dc:creator><pubDate>Tue, 04 Jul 2017 08:29:24 -0400</pubDate><guid>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type/2731</guid></item><item><title>Comment by Reguel Wermelinger on trungdv's question</title><link>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type#2641</link><description>&lt;p&gt;Currently there is no API in the axon.ivy core that would trigger an index-recreation or schema update on the ElasticSearch server. 
But you could basically flush the whole ElasticSearch index and trigger the axon.ivy engine to synchronize its data again with the ElasticSearch index. The API to do so is here: &lt;code&gt;ch.ivyteam.ivy.business.data.store.restricted.IBusinessDataManager.startIndexRecreation()&lt;/code&gt;. 
There is also a built in mechanism on axon.ivy engine startup that synchronizes the indexes if the ElasticSeach index is not up to date.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Reguel Wermelinger</dc:creator><pubDate>Fri, 26 May 2017 05:19:31 -0400</pubDate><guid>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type#2641</guid></item><item><title>Comment by trungdv on trungdv's question</title><link>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type#2638</link><description>&lt;p&gt;i have found the root cause. it's because on new version &lt;strong&gt;we just changed the type of property&lt;/strong&gt; &lt;code&gt;qualificationMessageResults.message&lt;/code&gt; &lt;strong&gt;from String to an object&lt;/strong&gt; type, so it lead to issue that when we deploy this version to server, the old business data (where message is still String type) can not be index anymore. And it throw exception unknow property descriptor.&lt;/p&gt;
&lt;p&gt;Problematic is that ElasticSearch already determined the type of this field as string.
I heard elasticsearch has way to reindex, does ivy support it?&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">trungdv</dc:creator><pubDate>Thu, 25 May 2017 22:01:36 -0400</pubDate><guid>https://answers.axonivy.com/questions/2606/can-not-persist-business-data-to-repo-after-changing-data-type#2638</guid></item></channel></rss>