Broadleaf Microservices

Displaying a New Field with Broadleaf Metadata

In this tutorial, we will cover how to add a new field to an exiting entity’s metadata. Let’s add a preferredCommunicationMethod enum field to Customer.

Tip
For a more in-depth look at Broadleaf metadata, Check out the Unified Admin docs.
Note
Custom metadata should go in MicroservicesDemo/services/metadata. You should make a different package for each service’s custom metadata such as com.broadleafdemo.metadata.customer or com.broadleafdemo.metadata.catalog.

Adding an Enum

First, let’s define our enum values. We’ll be implementing SelectOption.SelectOptionEnum to help us set the metadata up correctly. This will have a method to convert each Java enum value into a SelectOption representing an option used by a SelectField component in the Admin.

PreferredCommunicationMethodOptionEnum.java
package com.broadleafdemo.metadata.customer.support;

import com.broadleafcommerce.metadata.dsl.core.extension.fields.SelectOption;

import java.util.List;

public enum PreferredCommunicationMethodOptionEnum implements SelectOption.SelectOptionEnum {

    PHONE("custom.customer.preferredCommunicationMethod.phone", "primary"),
    TEXT("custom.customer.preferredCommunicationMethod.text", "primary"),
    EMAIL("custom.customer.preferredCommunicationMethod.email", "primary");

    PreferredCommunicationMethodOptionEnum(String label, String color) {
        this.label = label;
        this.color = color;
    }

    /**
     * This is displayed to the user and can be a message property key to support localized
     * translations.
     */
    private String label;

    /**
     * Options can be differentiated by color as well. This should reference a color that the Admin
     * client understands such as {@code primary}, {@code gray}, {@code green}, etc. It defaults to
     * {@code default}, which means the default text color.
     */
    private String color;

    @Override
    public String label() {
        return label;
    }

    @Override
    public String color() {
        return color;
    }

    /**
     * Factory method to generate a set of {@link SelectOption} from this enumeration. This will be
     * referenced in the metadata DSL for the related field to let the Admin know what values a
     * user can choose from.
     *
     * @return the set of options
     */
    public static List<SelectOption> toOptions() {
        return SelectOption.fromEnums(values());
    }

}

Adding Localized Messages

Next, let’s look at adding the localized text in Sprint message properties files. We’ll place these in resources/messages/customer/custom-customer.properties.

Tip
We’ll be adding just English text as the default. For translations, create property files in the same place but with the appropriate locale code as the suffix such as custom-customer_es.properties for Spanish translations and custom-customer_fr.properties for French.
custom-customer.properties
# enum value labels
custom.customer.preferredCommunicationMethod.phone=Call
custom.customer.preferredCommunicationMethod.text=Text
custom.customer.preferredCommunicationMethod.email=Email

# field label
custom.customer.preferredCommunicationMethod=Preferred Communication Method

To load these, we’ll add a MetadataMessagesBasename configuration class. This can be used to reference all custom messages files not just for customer, so we’ll move it out of the customer package into metadata.i18n.

package com.broadleafdemo.metadata.i18n;

import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;

import com.broadleafcommerce.metadata.i18n.MetadataMessagesBasename;

import java.util.Arrays;

public class CustomMetadataMessages implements MetadataMessagesBasename {

    @Override
    @NonNull
    public String getBasename() {
        return StringUtils.join(Arrays.asList("messages/customer/custom-customer"), ",");
    }
}

Then we add this to resources/META-INF/spring.factories in metadata.

com.broadleafcommerce.metadata.i18n.MetadataMessagesBasename=\
  com.broadleafdemo.metadata.i18n.CustomMetadataMessages

Adding the new field using the DSL

Finally, let’s actually add the new field definition to the base metadata use the DSL. All components are registered with the application using ComponentSource beans. This is a functional interface that takes the registry of components as the input, which can be searched for already registered components or updated to include new ones.

CustomerMetadataConfiguration.java
package com.broadleafdemo.metadata.customer;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.broadleafdemo.metadata.customer.support.PreferredCommunicationMethodOptionEnum;
import com.broadleafcommerce.customer.metadata.customer.support.CustomerIds;
import com.broadleafcommerce.metadata.dsl.core.extension.views.details.CreateEntityView;
import com.broadleafcommerce.metadata.dsl.core.extension.views.details.EntityFormView;
import com.broadleafcommerce.metadata.dsl.core.extension.views.details.UpdateEntityView;
import com.broadleafcommerce.metadata.dsl.core.utils.Fields;
import com.broadleafcommerce.metadata.dsl.registry.ComponentSource;

@Configuration
public class CustomerMetadataConfig {

    static class CustomProps {
        public static final String PREFERRED_COMMUNICATION_METHOD = "preferredCommunicationMethod";
    }

    @Bean
    public ComponentSource customCustomerMetadataComponents() {
        return registry -> {
            // find the create form
            CreateEntityView<?> customerCreate =
                    (CreateEntityView<?>) registry.get(CustomerIds.CREATE);
            // apply the updates
            customerCreate.getGeneralForm()
                    .apply(this::modifyGeneralForm);

            // find the update form
            UpdateEntityView<?> customerUpdate =
                    (UpdateEntityView<?>) registry.get(CustomerIds.UPDATE);
            // apply the updates
            customerUpdate.getGeneralForm()
                    .apply(this::modifyGeneralForm);
        };
    }

    protected EntityFormView<?> modifyGeneralForm(EntityFormView<?> form) {
        return form
                .addField(CustomProps.PREFERRED_COMMUNICATION_METHOD, Fields.select()
                        .label("custom.customer.preferredCommunicationMethod")
                        // refer back to our enum and call `#toOptions()`
                        .options(PreferredCommunicationMethodOptionEnum.toOptions())
                        // and we'll go ahead and set the default value
                        .defaultValue(PreferredCommunicationMethodOptionEnum.PHONE.name())
                        .order(2000));
    }

}