安全的方式从字符串转换为Jackson的策略。

huangapple go评论69阅读模式
英文:

Type safe way to go from a String to a Strategy with Jackson

问题

我想执行带有过滤器的查询,从 UI 开始,基于逻辑运算符 (>20)。

目前,逻辑运算符 (匹配器) 是 Jackson 映射到枚举的常量。
然后我有一个大型的模式匹配开关,将每个枚举映射到一个函数。
使用 Hibernate Criteria Builder 生成谓词的函数。
这通常是一个实用的简单解决方案,但是长长的开关语句最终会变得难以管理。

地图查找也没有更好,因为你必须首先将地图配置为大块文本,本质上与大型模式匹配开关没有区别。

因此,我正在寻找一种安全的方式,可以从 JSON 文件中的字符串转换为具体的实现策略,例如从 "TEXT_EQUALS_" 到 TextEqualsMatcher,它可以使用 CriteriaBuilder 方法参数构建 Hibernate 谓词。

是的,这将强烈地将 JSON 与 Hibernate 耦合起来 - 但我认为无论如何都存在耦合,因为我们有数据库过滤器 - 在我看来,一个非常精简的实现没有任何查找的优点可能会证明其合理性。

所以基本上我正在寻找一种从这个安全类型的方法:

{
  "type": "field",
  "id": "104e578c-6841-48e5-8ee0-927a1eaa0fbe",
  "value": "Ukraine",
  "matcher": "text_equals"
}

到这个的方式:

public class TextEqualsMatcher implements FieldMatcher {
    @Override
    public Predicate toPredicate(CriteriaBuilder cb, Path<String> path) {
        // 构建并返回 Text Equals 条件的谓词的逻辑
    }
}

代码可能是这样的:
public interface Filter {
    Predicate toPredicate(CriteriaBuilder cb, Path<String> path);
}

@JsonTypeName("field")
public record FieldElement(
        @JsonProperty("id") UUID id,
        @JsonProperty("value") String value,
        @JsonProperty("matcher") FieldMatcher matcher
) implements Filter {
    public Predicate toPredicate(CriteriaBuilder cb, Path<String> path) {
        return matcher.toPredicate(cb, path, value);
    }
}

public interface FieldMatcher {
    Predicate toPredicate(CriteriaBuilder cb, Path<String> path, String value);
}

@JsonTypeName("text_equals")
public class TextEqualsMatcher implements FieldMatcher {
    public Predicate toPredicate(CriteriaBuilder cb, Path<String> path, String value) {
        // 构建并返回 Text Equals 条件的谓词的逻辑
    }
}

所以我猜一个带有 Enum 常量的 @JsonTypeName 将会很棒:

@JsonTypeName(MatcherType.TEXT_EQUALS)

任何输入/想法?

英文:

I want to execute queries with filters, from UI, based on logical operators (>20).

Currently, the logical operator (matcher) is a constant that Jackson maps to an enum.
Then I have a large pattern-matching switch that then maps each enum to a function.
A function that generates a predicate using the Hibernate Criteria Builder.
This is generally a pragmatic simple solution - but the long switch statement eventually will become unmanageable.

A map lookup is no better because you would have to configure the map as big block of text first, which in essence is no different from a large pattern matching switch.

So I am looking for a type-safe way to go from a string in a json file to the concrete
implementing strategy, e.g from "TEXT_EQUALS_ to a TextEqualsMatcher that can build a Hibernate Predicate with a CriteriaBuilder method parameter.

Yes, this would strongly couple json to Hibernate -
but I think the coupling is there anyway, one way or another because we have database filters - and IMHO the advantages of a very lean implementation without any lookup could justify it

So basically I am looking for a type-safe way to go from this:

{
  "type": "field",
  "id": "104e578c-6841-48e5-8ee0-927a1eaa0fbe",
  "value": "Ukraine",
  "matcher": "text_equals"
}

to this:

public class TextEqualsMatcher implements FieldMatcher {
    @Override
    public Predicate toPredicate(CriteriaBuilder cb, Path<String> path) {
        // Logic to build and return the predicate for the Text Equals condition
    }
}

The code would probably be something like this:
public interface Filter {
    Predicate toPredicate(CriteriaBuilder cb, Path<String> path);
}

@JsonTypeName("field")
public record FieldElement(
        @JsonProperty("id") UUID id,
        @JsonProperty("value") String value,
        @JsonProperty("matcher") FieldMatcher matcher
) implements Filter {
    public Predicate toPredicate(CriteriaBuilder cb, Path<String> path) {
        return matcher.toPredicate(cb, path, value);
    }
}

public interface FieldMatcher {
    Predicate toPredicate(CriteriaBuilder cb, Path<String> path, String value);
}

@JsonTypeName("text_equals")
public class TextEqualsMatcher implements FieldMatcher {
    public Predicate toPredicate(CriteriaBuilder cb, Path<String> path, String value) {
        // Logic to build and return the predicate for the Text Equals condition
    }
}

So a @JsonTypeName with an Enum constant would be great I guess:

@JsonTypeName(MatcherType.TEXT_EQUALS)

Any input/ideas?

答案1

得分: 1

这似乎是可行的:您确实需要在基接口中添加@JsonTypeInfo(以指示多态处理),并且还需要从基类型到子类型的@JsonSubTypes引用(这有点不太幸运)。
但是有了这些,似乎事情应该可以工作?

英文:

It seems doable: you do need to add @JsonTypeInfo in base interfaces (to indicate polymorphic handling), and also @JsonSubTypes references from base- to sub-types (which is bit unfortunate).
But with that it seems things should work?

huangapple
  • 本文由 发表于 2023年5月10日 16:42:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76216481.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定