Creating content fragment models programatically fails to set array | Community
Skip to main content
April 11, 2025
Solved

Creating content fragment models programatically fails to set array

  • April 11, 2025
  • 1 reply
  • 498 views

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

Best answer by sarav_prakash

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 

Hope this helps. 

1 reply

sarav_prakash
Community Advisor
Community Advisor
April 14, 2025

element.setContent requires 2 params. You must set as 

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

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

sarav_prakash
Community Advisor
sarav_prakashCommunity AdvisorAccepted solution
Community Advisor
April 18, 2025

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 

Hope this helps.