Skip to content

How to create custom Modifiers in Quarkus? #1289

@victorLessa

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions