Skip to content

How to create custom Modifiers in Quarkus? #1289

Description

@victorLessa

Analyzing question #1079, I tried to implement the custom modifier in Quarkus following the instructions, but without a positive effect, I receive the error:

"JOLT Chainr could not find transform class: **.**.**.**.**.**.jolt.CustomModifier$Overwritr.class at index:1."

Quarkus Version: 3.19.4
Jolt verson:

<dependency>
	<groupId>com.bazaarvoice.jolt</groupId>
	<artifactId>jolt-core</artifactId>
	<version>0.1.6</version>
</dependency>
<dependency>
	<groupId>com.bazaarvoice.jolt</groupId>
	<artifactId>json-utils</artifactId>
	<version>0.1.6</version>
</dependency>

My Spec:

[
  {
    "operation": "shift",
    "spec": {
      "*": "&"
    }
  },
  {
    "operation": "**.**.**.**.**.**.jolt.CustomModifier$Overwritr",
    "spec": {
      "prompts": "=stringfy(@(0))"
    }
  }
]

My CustomFunction

import com.bazaarvoice.jolt.common.Optional;
import com.bazaarvoice.jolt.modifier.function.Function;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class CustomFunctions {

    public static final class stringfy extends Function.SingleFunction<Object> {

        @Override
        protected Optional<Object> applySingle(Object o) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                String stringValue = objectMapper.writeValueAsString(o);
                return Optional.of(stringValue);
            } catch (JsonProcessingException e) {
                return Optional.empty();
            }
        }
    }
}

My CustomModifier

import com.bazaarvoice.jolt.ContextualTransform;
import com.bazaarvoice.jolt.SpecDriven;
import com.bazaarvoice.jolt.common.Optional;
import com.bazaarvoice.jolt.common.tree.MatchedElement;
import com.bazaarvoice.jolt.common.tree.WalkedPath;
import com.bazaarvoice.jolt.exception.SpecException;
import com.bazaarvoice.jolt.modifier.OpMode;
import com.bazaarvoice.jolt.modifier.TemplatrSpecBuilder;
import com.bazaarvoice.jolt.modifier.function.Function;
import com.bazaarvoice.jolt.modifier.spec.ModifierCompositeSpec;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class CustomModifier implements SpecDriven, ContextualTransform {

    private static final Map<String, Function> STOCK_FUNCTIONS = new HashMap<>();

    private final ModifierCompositeSpec rootSpec;

    static {
        STOCK_FUNCTIONS.put("stringfy", new CustomFunctions.stringfy());
    }

    private CustomModifier(Object spec, OpMode opMode, Map<String, Function> functionsMap) {
        if (spec == null) {
            throw new SpecException(opMode.name() + " expected a spec of Map type, got 'null'.");
        }

        if (!(spec instanceof Map)) {
            throw new SpecException(
                    opMode.name() + " expected a spec of Map type, got " + spec.getClass().getSimpleName());
        }

        if (functionsMap == null || functionsMap.isEmpty()) {
            throw new SpecException(opMode.name() + " expected a populated functions' map type, got "
                    + (functionsMap == null ? "null" : "empty"));
        }

        functionsMap = Collections.unmodifiableMap(functionsMap);
        TemplatrSpecBuilder templatrSpecBuilder = new TemplatrSpecBuilder(opMode, functionsMap);

        rootSpec = new ModifierCompositeSpec(ROOT_KEY, (Map<String, Object>) spec, opMode, templatrSpecBuilder);
    }

    @Override
    public Object transform(final Object input, final Map<String, Object> context) {

        Map<String, Object> contextWrapper = new HashMap<>();
        contextWrapper.put(ROOT_KEY, context);

        MatchedElement rootLpe = new MatchedElement(ROOT_KEY);
        WalkedPath walkedPath = new WalkedPath();
        walkedPath.add(input, rootLpe);

        rootSpec.apply(ROOT_KEY, Optional.of(input), walkedPath, null, contextWrapper);

        return input;
    }

    /**
     * This variant of modifier creates the key/index is missing,
     * and overwrites the value if present
     */
    public static final class Overwritr extends CustomModifier {

        public Overwritr(Object spec) {
            this(spec, STOCK_FUNCTIONS);
        }

        public Overwritr(Object spec, Map<String, Function> functionsMap) {
            super(spec, OpMode.OVERWRITR, functionsMap);
        }
    }

    /**
     * This variant of modifier only writes when the key/index is missing
     */
    public static final class Definr extends CustomModifier {

        public Definr(final Object spec) {
            this(spec, STOCK_FUNCTIONS);
        }

        public Definr(Object spec, Map<String, Function> functionsMap) {
            super(spec, OpMode.DEFINER, functionsMap);
        }
    }

    /**
     * This variant of modifier only writes when the key/index is missing or the
     * value is null
     */
    public static class Defaultr extends CustomModifier {

        public Defaultr(final Object spec) {
            this(spec, STOCK_FUNCTIONS);
        }

        public Defaultr(Object spec, Map<String, Function> functionsMap) {
            super(spec, OpMode.DEFAULTR, functionsMap);
        }
    }

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions