有一个Lombok注解可以将类的所有字段获取为Object数组吗?

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

Is there a Lombok annotation to get all fields of an object of a class as an Object array?

问题

我有一个表示数据库表的主键(复合主键)的类。

@Value
public class ItemPrimaryKey {
    String compositeKeyColumnA;
    String compositeKeyColumnB;
    String compositeKeyColumnC;
    String compositeKeyColumnD;
}

当我想要通过主键从表中读取一行时,我应该执行以下操作:

jdbcTemplate.query(
    READ_ITEM_BY_PK_QUERY,
    new BeanPropertyRowMapper<>(Item.class),
    itemPrimaryKey.getCompositeKeyColumnA(),
    itemPrimaryKey.getCompositeKeyColumnB(),
    itemPrimaryKey.getCompositeKeyColumnC(),
    itemPrimaryKey.getCompositeKeyColumnD());

然而,由于JdbcTemplatequery方法将Object...作为其最后一个参数,我可以这样做:

public class ItemPrimaryKey {
    // ...
    public Object[] getForVarArgs() {
        return new Object[] { compositeKeyColumnA, compositeKeyColumnB, compositeKeyColumnC, compositeKeyColumnD };
    }
}
jdbcTemplate.query(
    READ_ITEM_BY_PK_QUERY,
    new BeanPropertyRowMapper<>(Item.class),
    itemPrimaryKey.getForVarArgs());

由于我在多个类/数据库表中都有类似的情况,如果可能的话,我希望能够通过使用Lombok注解来实现。是否有这样的注解?

我已经查阅了Lombok的文档,并进行了谷歌搜索,但我没有找到这样的注解。然而,也许有一个现有注解的配置仍然可以实现这个目标?

英文:

I have a class which represents the primary key (which is a composite one) of a database table.

@Value
public class ItemPrimaryKey {
    String compositeKeyColumnA;
    String compositeKeyColumnB;
    String compositeKeyColumnC;
    String compositeKeyColumnD;
}

When I want to read a row from the table by primary key, I should do the following:

jdbcTemplate.query(
    READ_ITEM_BY_PK_QUERY,
    new BeanPropertyRowMapper<>(Item.class),
    itemPrimaryKey.getCompositeKeyColumnA(),
    itemPrimaryKey.getCompositeKeyColumnB(),
    itemPrimaryKey.getCompositeKeyColumnC(),
    itemPrimaryKey.getCompositeKeyColumnD());

However, because the query method of JdbcTemplate takes Object... as its last parameter, I can do the following:

public class ItemPrimaryKey {
    // ...
    public Object[] getForVarArgs() {
        return new Object[] { compositeKeyColumnA, compositeKeyColumnB, compositeKeyColumnC, compositeKeyColumnD };
    }
}
jdbcTemplate.query(
    READ_ITEM_BY_PK_QUERY,
    new BeanPropertyRowMapper<>(Item.class),
    itemPrimaryKey.getForVarArgs());

Since I have the above situation for multiple classes/DB tables, I would like to achieve it with a Lombok annotation, if possible. Is there one that does this?

I have looked through Lombok's documentation, and googled, but I found no such thing. However, maybe there is a configuration for an existing annotation that could still achieve this?

答案1

得分: 1

我已经对trandafir-emanuel的回答进行了调整,以实现我认为最简单的解决方案。只需让类扩展这个抽象类,它们将可以立即使用toVarArgs()(之前称为getForVarArgs() - 我不得不将其重命名为不以get开头的名称,否则Jackson在序列化期间会尝试使用该方法)。

此外,字段的定义顺序得到了尊重,在这种情况下显然很重要。

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.LinkedHashMap;
import java.util.Map;

abstract class VarArgsConvertible {
    private Object[] thisAsVarArgs = null;

    public Object[] toVarArgs() {
        if (thisAsVarArgs == null) {
            Map<?, ?> thisAsMap = new ObjectMapper().convertValue(this, LinkedHashMap.class);
            thisAsVarArgs = thisAsMap.values().toArray();
        }

        return thisAsVarArgs;
    }
}
英文:

I have adapted trandafir-emanuel's answer to the simplest possible solution I could think of. Classes only need to extend this abstract class, and they'll have toVarArgs() working out of the box (previously called getForVarArgs() - I had to rename it to something not starting with get, because otherwise Jackson tried to use the method during serialization).

Also, the order of definition of the fields is respected, which is clearly important in this case.

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.LinkedHashMap;
import java.util.Map;

abstract class VarArgsConvertible {
    private Object[] thisAsVarArgs = null;

    public Object[] toVarArgs() {
        if (thisAsVarArgs == null) {
            Map&lt;?, ?&gt; thisAsMap = new ObjectMapper().convertValue(this, LinkedHashMap.class);
            thisAsVarArgs = thisAsMap.values().toArray();
        }

        return thisAsVarArgs;
    }
}

答案2

得分: 0

I am not aware of solutions with lombok, but there are alternatives.

虽然我不清楚使用Lombok的解决方案,但有替代方案。

Though it might not be a beautiful solutiuon, you can invoke the getter-methods from your class through reflection:

尽管这可能不是一个优美的解决方案,但你可以通过反射来调用你的类中的getter方法:

        Object[] objects = Arrays.stream(ItemPrimaryKey.class.getMethods())
                .filter(method -> Pattern.compile("getCompositeKeyColumn.").matcher(method.getName()).matches())
                .sorted(Comparator.comparing(Method::getName))
                .map(method -> {
                    try {
                        return method.invoke(itemPrimaryKey);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                })
                .toArray(Object[]::new);

Note that the order here is determined by sorting on the getter-name, which works with your specific example, but not generally. Also, the pattern might need adjustments if other fields in the class is needed.

请注意,这里的顺序是通过对getter名称进行排序确定的,这适用于您的特定示例,但不适用于通用情况。此外,如果需要类中的其他字段,模式可能需要进行调整。

However, at this point, you might be better off by creating an instance method in your class which returns the fields in an array.

然而,在这一点上,你最好创建一个实例方法,在你的类中返回一个字段数组。

英文:

I am not aware of solutions with lombok, but there are alternatives.

Though it might not be a beautiful solutiuon, you can invoke the getter-methods from your class through reflection:

        Object[] objects = Arrays.stream(ItemPrimaryKey.class.getMethods())
                .filter(method -&gt; Pattern.compile(&quot;getCompositeKeyColumn.&quot;).matcher(method.getName()).matches())
                .sorted(Comparator.comparing(Method::getName))
                .map(method -&gt; {
                    try {
                        return method.invoke(itemPrimaryKey);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                })
                .toArray(Object[]::new);

Note that the order here is determined by sorting on the getter-name, which works with your specific example, but not generally. Also, the pattern might need adjustments if other fields in the class is needed.

However, at this point, you might be better off by creating an instance method in your class which returns the fields in an array.

答案3

得分: 0

你无法使用Lombok来完成这个任务。如果你正在寻找替代方案,一种方法是使用Jackson将对象转换为HashMap,然后获取所有键:

private static String[] getFieldNames(Object obj) {
    Map<String, Object> map = new ObjectMapper().convertValue(obj, Map.class);
    return map.keySet().toArray(new String[0]);
}

不过,如果字段名不是动态变化的话,我更倾向于手动输入查询中的字段名。

英文:

you won't be able to do it with Lombok. If you are looking for alternatives, one way would be to convert the object to a hashmap using jackson, and then get all the keys:

private static String[] getFieldNames(Object obj) {
	Map&lt;String, Object&gt; map = new ObjectMapper().convertValue(obj, Map.class);
	return map.keySet().toArray();
}

though, I would rather manually enter the field names in the query, if it is not something that can dynamically change.

huangapple
  • 本文由 发表于 2023年3月1日 16:25:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75601146.html
匿名

发表评论

匿名网友

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

确定