Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.
SOLVED

Delegation Pattern for Title Component - what get method needs an Override?

Avatar

Level 2

Using AEM 6.5 SP1.  I followed the basic example here: Delegation Pattern for Sling Models · adobe/aem-core-wcm-components Wiki · GitHub

The example extended the title component and overwrote the getText() method in a PageHeadline class.  Do you also need to override all the other get methods of the OOTB delegated title component to use them in the HTL?  Or should the Delegation Pattern provide them all?

Using just the example, the Link functionality is not working properly.  The "page 1" link is just a proxy of the OOTB core title component v2.  The "Overriding the page 1" text is from the pageheadline component overriding just the getText() and getType() methods as per the example.  You can see the link is not working.

1809771_pastedImage_10.png

If I add an additional override for getLinkURL() to the PageHeadline.java, the link work starts working.

    @Override

    public String getLinkURL() {

        return title.getLinkURL();

}

1809773_pastedImage_14.png

I'm seeing the same thing with the JSON exporter.  With the example, the JSON is always the OOTB title component and does not show the overridden text from the pageheadline.

":items": {

"title": {

"linkDisabled": false,

"type": "h2",

"linkURL": "/content/my-testing/en.html",

"text": "page 1",

":type": "my-testing/components/content/title"

},

"pageheadline": {

"linkDisabled": false,

"type": "h2",

"linkURL": "/content/my-testing/en.html",

"text": "page 1",

":type": "my-testing/components/content/pageheadline"

}

}

I updated the PageHeadline.java code to add the adapter for ComponentExporter.class.

     adapters = {Title.class, ComponentExporter.class}

Now pageheadline only has the two methods getText() and getType() that were overriden in PageHeadline.java.  Should I need to add all the other methods to get them to show up in the JSON?  That does work, but now I have to add override stubs for every get method.  Or should the values come through the delegation?

":items": {

"title": {

"linkDisabled": false,

"type": "h2",

"linkURL": "/content/my-testing/en.html",

"text": "page 1",

":type": "my-testing/components/content/title"

},

"pageheadline": {

"type": "h2",

"text": "Overriding the page 1"

}

}

1 Accepted Solution

Avatar

Correct answer by
Level 10

Delegation is not inheritance

HTL can only access value exposed by conventionally named getters and setters. If your PageHeadLine does not expose those one way or another, then you will not be able to access those properties in your HTL template (same principle for the JSON export).

Since your PageHeadLine does not inherit from the Title core component, it will not inherit that component's getters and setters. When you try to access a value if HTL, it cannot "guess" that you want it to access that value via your delegate.

Example: imagine your component had two delegates:

@Self @Via(type = ResourceSuperType.class)

private Title title1;

and

@Self @Via(type = ResourceSuperType.class)

private Title title2;

Which one would you access via HTL, title1 or title2? You see, there is no way to guess unless its explicitly defined using an @Override.

What is really going on

Your class implements the Title interface. The reason you are not forced to @Override each and every method of the Title interface is because those methods are given a default implementation. Inspect the Title source code and you'll see the following:

@ConsumerType

public interface Title extends ComponentExporter {

  String PN_DESIGN_DEFAULT_TYPE = "type";
  String PN_TITLE_LINK_DISABLED = "linkDisabled";

  default String getText() {

  throw new UnsupportedOperationException();
  }

  default String getType() {

  throw new UnsupportedOperationException();
  }

  ...

}

In fact, every time you invoke one of those "un-overriden" methods (by attempting to accessing them via HTL for example), you are throwing an exception!

Good news, bad news

So the bad news news is yes, you will have to create delegate methods for all properties you want to re-use from the Title core component.

The good news is that your IDE might be able to do this for you. In Intellij, open your class and go to Code > Generate.. > Delegate methods, then select your delegate (title in your case) and select the methods to generate. Boom, the stubs are created for you   I don't use Eclipse, but the procedure is provided here.

View solution in original post

1 Reply

Avatar

Correct answer by
Level 10

Delegation is not inheritance

HTL can only access value exposed by conventionally named getters and setters. If your PageHeadLine does not expose those one way or another, then you will not be able to access those properties in your HTL template (same principle for the JSON export).

Since your PageHeadLine does not inherit from the Title core component, it will not inherit that component's getters and setters. When you try to access a value if HTL, it cannot "guess" that you want it to access that value via your delegate.

Example: imagine your component had two delegates:

@Self @Via(type = ResourceSuperType.class)

private Title title1;

and

@Self @Via(type = ResourceSuperType.class)

private Title title2;

Which one would you access via HTL, title1 or title2? You see, there is no way to guess unless its explicitly defined using an @Override.

What is really going on

Your class implements the Title interface. The reason you are not forced to @Override each and every method of the Title interface is because those methods are given a default implementation. Inspect the Title source code and you'll see the following:

@ConsumerType

public interface Title extends ComponentExporter {

  String PN_DESIGN_DEFAULT_TYPE = "type";
  String PN_TITLE_LINK_DISABLED = "linkDisabled";

  default String getText() {

  throw new UnsupportedOperationException();
  }

  default String getType() {

  throw new UnsupportedOperationException();
  }

  ...

}

In fact, every time you invoke one of those "un-overriden" methods (by attempting to accessing them via HTL for example), you are throwing an exception!

Good news, bad news

So the bad news news is yes, you will have to create delegate methods for all properties you want to re-use from the Title core component.

The good news is that your IDE might be able to do this for you. In Intellij, open your class and go to Code > Generate.. > Delegate methods, then select your delegate (title in your case) and select the methods to generate. Boom, the stubs are created for you   I don't use Eclipse, but the procedure is provided here.