Expand my Community achievements bar.

Join expert-led, customer-led sessions on Adobe Experience Manager Assets on August 20th at our Skill Exchange.
SOLVED

Creating content fragment models programatically fails to set array

Avatar

Level 3

I want to create a content fragment instance, but setting an array of field paths is not working.

 

the code is creating the fragment and all other fields are being set correctly, but when I try and set a multi field fragment reference it isn't setting the value.

 

An example I followed had this code:

private void setField(ContentFragment newFragment, String field, Object value) throws ContentFragmentException {

ContentElement element = newFragment.getElement(field);

String contentType = element.getContentType();

if (value instanceof String) {

element.setContent((String) value, contentType);

} else if (value instanceof String[]) {

String[] values = (String[]) value;

element.setContent(String.join(",", values), contentType);

}

}

 

However all that gets set is the first element of the array with a string concatenation.

 

I tried changing it to

private void setField(ContentFragment newFragment, String field, Object value) throws ContentFragmentException {

ContentElement element = newFragment.getElement(field);

String contentType = element.getContentType();

if (value instanceof String) {

element.setContent((String) value, contentType);

} else if (value instanceof String[]) {

FragmentData data = element.getValue();

if (data != null) {

data.setValue(value);

}

}

}

 

But this failed to set a value.

I have checked the fragmentData with:

System.out.println(data.getContentType()+":"+data.getDataType().isMultiValue());

and it outputs text/plain:true

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @taggatmerkle ,

Sorry for late reply. Yes OOTB is string. But we created custom datatype to allow String[]. 

Here is the snippet 

String[] test = new String[]{"test2", "test3", "test25"};
        Optional.ofNullable(slingRequest.getResourceResolver().getResource("/content/dam/web/qa/mynav"))
                .map(cf -> cf.adaptTo(ContentFragment.class))
                .map(cf -> cf.getElement("testMultiStringProperty"))
                .ifPresent(ele -> {
                    try {
                        MultiValuedFragmentData data = new MultiValuedFragmentData();
                        data.setValue(test);
                        ele.setValue(data);
                    } catch (ContentFragmentException e) {
                        LOG.error(e.getMessage(), e);
                    }
                });

Here MultiValuedFragmentData class is 

package com.my.core.data;

import java.util.Calendar;

import com.adobe.cq.dam.cfm.DataType;
import com.adobe.cq.dam.cfm.FragmentData;

public class MultiValuedFragmentData implements FragmentData {
    private Object value;
    private String contentType;
    private Calendar lastModified;
    private String lastModifiedBy;

    @Override
    public DataType getDataType() {
        return new MultiStringDataType();
    }

    @Override
    public <T> T getValue(Class<T> var1) {
        return var1.cast(value);
    }

    @Override
    public boolean isTypeSupported(Class var1) {
        return true;
    }

    @Override
    public Object getValue() {
        return value;
    }

    @Override
    public void setValue(Object var1) {
        this.value = var1;
    }

    @Override
    public String getContentType() {
        return contentType;
    }

    @Override
    public void setContentType(String var1) {
        this.contentType = var1;
    }

    @Override
    public Calendar getLastModified() {
        return lastModified;
    }

    @Override
    public String getLastModifiedBy() {
        return lastModifiedBy;
    }

}

and MultiStringDataType is 

package com.my.core.data;

import com.adobe.cq.dam.cfm.DataType;

public class MultiStringDataType implements DataType {

  @Override
  public String getValueType() {
    return String[].class.getName();
  }

  @Override
  public String getSemanticType() {
    return "multi-string";
  }

  @Override
  public boolean isMultiValue() {
    return true;
  }


  @Override
  public String getTypeString() {
    return "String[]";
  }

}

When I call the first method from a servlet, it produced this output 

sarav_prakash_0-1744935811418.png

Hope this helps. 

View solution in original post

3 Replies

Avatar

Community Advisor

element.setContent requires 2 params. You must set as 

element.setContent(values, contentType); // values is String[]

Avatar

Level 3

element.setContent only accepts a string. this works fine for standard content.

 

I have done a workaround

private void setField(ContentFragment newFragment, String field, Object value) throws ContentFragmentException {

ContentElement element = newFragment.getElement(field);

String contentType = element.getContentType();

if (value instanceof String) {

element.setContent((String) value, contentType);

} else if (value instanceof String[]) {

element.getValue().setValue(value);

ModifiableValueMap mvm =newFragment.adaptTo(Resource.class).getChild("jcr:content/data/master").adaptTo(ModifiableValueMap.class);

mvm.put(field, value);

}

 

}

While this works, it is messy and I would prefer to be using the ContentElement or FragmentData, but can't get that to save the value

Avatar

Correct answer by
Community Advisor

Hi @taggatmerkle ,

Sorry for late reply. Yes OOTB is string. But we created custom datatype to allow String[]. 

Here is the snippet 

String[] test = new String[]{"test2", "test3", "test25"};
        Optional.ofNullable(slingRequest.getResourceResolver().getResource("/content/dam/web/qa/mynav"))
                .map(cf -> cf.adaptTo(ContentFragment.class))
                .map(cf -> cf.getElement("testMultiStringProperty"))
                .ifPresent(ele -> {
                    try {
                        MultiValuedFragmentData data = new MultiValuedFragmentData();
                        data.setValue(test);
                        ele.setValue(data);
                    } catch (ContentFragmentException e) {
                        LOG.error(e.getMessage(), e);
                    }
                });

Here MultiValuedFragmentData class is 

package com.my.core.data;

import java.util.Calendar;

import com.adobe.cq.dam.cfm.DataType;
import com.adobe.cq.dam.cfm.FragmentData;

public class MultiValuedFragmentData implements FragmentData {
    private Object value;
    private String contentType;
    private Calendar lastModified;
    private String lastModifiedBy;

    @Override
    public DataType getDataType() {
        return new MultiStringDataType();
    }

    @Override
    public <T> T getValue(Class<T> var1) {
        return var1.cast(value);
    }

    @Override
    public boolean isTypeSupported(Class var1) {
        return true;
    }

    @Override
    public Object getValue() {
        return value;
    }

    @Override
    public void setValue(Object var1) {
        this.value = var1;
    }

    @Override
    public String getContentType() {
        return contentType;
    }

    @Override
    public void setContentType(String var1) {
        this.contentType = var1;
    }

    @Override
    public Calendar getLastModified() {
        return lastModified;
    }

    @Override
    public String getLastModifiedBy() {
        return lastModifiedBy;
    }

}

and MultiStringDataType is 

package com.my.core.data;

import com.adobe.cq.dam.cfm.DataType;

public class MultiStringDataType implements DataType {

  @Override
  public String getValueType() {
    return String[].class.getName();
  }

  @Override
  public String getSemanticType() {
    return "multi-string";
  }

  @Override
  public boolean isMultiValue() {
    return true;
  }


  @Override
  public String getTypeString() {
    return "String[]";
  }

}

When I call the first method from a servlet, it produced this output 

sarav_prakash_0-1744935811418.png

Hope this helps.