Expand my Community achievements bar.

Learn about Edge Delivery Services in upcoming GEM session

Override JSON Serialization inside SPA Page model request

Avatar

Level 4

Hey folks,


I'm working on an implementation for custom Sling Model exporters that rely on a GSON-based export framework we've built. What I want to do is change the way the JSON serialization happens every time this component is serialized.

 

I have it working so that if I fetch the component directly:

 

http://localhost:4502/content/my-app/us/en/jcr:content/root/container/container/section_container/mycomponent_54231355.model.json

 

 

I get the custom JSON I am expecting. However, if I fetch the page:

 

http://localhost:4502/content/my-app/us/en.model.json

 

 

Then I just get the OOTB serialization for this component (which is nested in the child components for the page).

 

How can I override the way this component is serialized including as part of the full page JSON?

 

My component:

 

@Model(
    resourceType = Breadcrumb.RESOURCE_TYPE,
    adaptables = {
        Resource.class,
        SlingHttpServletRequest.class
    }
)
@Exporter(
    name = CustomSlingModelExporter.NAME,
    extensions = ExporterConstants.SLING_MODEL_EXTENSION
)
public class Breadcrumb extends Component {
    public static final String RESOURCE_TYPE = "my-app/components/breadcrumb";

    // other fields and methods
}

 

 

The exporter:

 

@org.osgi.service.component.annotations.Component(service = ModelExporter.class)
public class CustomSlingModelExporter implements ModelExporter {
    public static final String NAME = "gson";

    
    public <T> T export(@NotNull Object model,  Class<T> clazz,  Map<String, String> options) throws org.apache.sling.models.factory.ExportException {
        return (T) new Gson().toJson(model);
    }

    
    public  String getName() {
        return NAME;
    }

    
    public boolean isSupported(@NotNull Class<?> clazz) {
        return clazz.equals(String.class);
    }
}

 

 

 

7 Replies

Avatar

Level 4

Hi Santosh,


I have reviewed the documents here but it doesn't explain why the code I have above does not work when requesting the full page. As far as I can tell, I've done what should be required, but I am still getting default (jackson) serialization when fetched at the page level.

Avatar

Community Advisor

@jamiec4451712 - Just to double check - I believe you have specified name and extension eg.

@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL, resourceType = {
		"weretail/components/content/text" })

@Exporter(name = "jackson" , extensions = "json")
public class RickTextModel {
	
	@ValueMapValue
	private String text;

	
	@JsonRawValue
	public String getText() {
		return StringEscapeUtils.unescapeHtml4(text).replaceAll("\\<.*?\\>", "");
	}

}

Avatar

Level 4

Hi Santosh,


Yes I've specified the name of my custom exporter and the "json" extension. I did not modify the "selector" as I want this to still be ".model.". 

 

Here are the annotations on my Sling Model:

@Model(
    resourceType = MyComponent.RESOURCE_TYPE,
    adaptables = {
        Resource.class,
        SlingHttpServletRequest.class
    }
)
@Exporter(
    // default selector = "model"
    name = ComponentSlingModelExporter.NAME, // this is "gson"
    extensions = ExporterConstants.SLING_MODEL_EXTENSION // this is "json"
)
public class MyComponent {

}

But I don't want to use "jackson", I want to use this custom exporter instead, but just for this component. So, for example, the page JSON will be 99% Jackson serialized, and this component will be GSON serialized.

Avatar

Level 4

Hi Santosh,

 

Thanks, I have seen this page before. This is similar to what I am doing, but uses the exporter directly on the page resourceType, which is not what I want to do. I want to let the OOTB model exporter for the Page keep working, but as it serializes the components on that page I want to be able to override them individually, or leave them using the OOTB workflow.

 

What seems odd to me is that understanding how the AEM SPA framework works, this seems like the most common use case for Sling Exporters, but I cannot find a single example online of this pattern. If the SPA loads the whole page model (json) and uses it to render the page, how would developers change the behaviour of one component without rewriting the exporter for the entire page?

Avatar

Level 4

Hi @jamiec4451712 

 

 Were you able to find the solution to the problem?

or how you solved this at last ?

 

Please share if you have any code snippets or way to fix.

 

Thank you