当前位置: 首页 > 知识库问答 >
问题:

使用Step Builder创建Tebuddy

安承教
2023-03-14

我试图让ByteBuddy实现一个步骤构建器,给定该构建器的接口。我被困在两个地方。

  1. 如何创建一个setter来返回方法链接的当前实例

我从以下几点开始:

.method(ElementMatchers.isSetter())
.intercept(FieldAccessor.ofBeanProperty());

只有我想返回当前的构建器实例,这样我们就可以像这样链接调用:

final Object obj = ...builder().id(100).name("test").build();

因此,我创建了一个这样的拦截器,看起来像是一个黑客,我希望尽可能避免反射:

@RuntimeType
public Object intercept(@RuntimeType Object arg, @This Object source, @Origin Method method)
{
  try
  {
    // Field name is same as method name.
    final Field field = source.getClass().getDeclaredField(method.getName());
    field.setAccessible(true);
    field.set(source, arg);
  }
  catch (Throwable ex)
  {
    throw new Error(ex);
  }

  // Return current builder instance.
  return source;
}

目前,我在一个循环中将字段添加到生成器类中,我在生成器上的构建方法被截取如下:

private static final class InterBuilder
{
  private final Collection<String> fields;
  private final Constructor<?> constructor;

  InterBuilder(final Constructor<?> constructor, final Collection<String> fields)
  {
    this.constructor = constructor;
    this.fields = fields;
  }

  @RuntimeType
  public Object intercept(@This Object source, @Origin Method method)
  {
    try
    {
      final Object[] args = Arrays.stream(source.getClass().getDeclaredFields())
        .filter(f -> this.fields.contains(f.getName()))
        .map(f ->  { try {
          f.setAccessible(true);
          return f.get(source); }
          catch (Throwable ex) { throw new Error(ex); } })
        .toArray();

      // Invoke a constructor passing in the private field values from the builder...
      return this.constructor.newInstance(args);
    }
    catch (Throwable ex)
    {
      throw new Error(ex);
    }
  }
}

我看到了@FieldValue注释。我不认为有什么东西会在不知道它们的名字的情况下给我所有字段?

该代码在这一点上是一个概念证明。有更好的方法来做我在这里做的事情吗<谢谢!

共有2个答案

谭修然
2023-03-14

拉斐尔给了我想出解决方案所需的信息,所以答案归功于他,但我想把我的解决方案包括在内,让其他人在未来发现。

DynamicType.Builder<?> builder = new ByteBuddy()
  .subclass(Object.class)
  .implement(interfaces)
  .name(builderClassName);

// Find all of the setters on the builder...  
// Here I'm assuming all field names match setter names like:
//   MyClass x = theBuilder.name("hi").id(1000).isValid(true).build();
final List<Method> setters = ...

for (final Method setter : setters)
{
  // This will define a field and a setter that will set the value and return the current instance.
  builder = builder
    .defineField(setter.getName(), setter.getParameterTypes()[0], Visibility.PRIVATE)
    .define(setter)
    .intercept(FieldAccessor.ofField(setter.getName()).setsArgumentAt(0).andThen(FixedValue.self()));
}

// Find the "build" method on the builder.
final Method buildMethod = ...

// Get a constructor that you want the builder to call and return the new instance.
final Constructor<?> constructor = ...

// Get the field names from the setters.
final List<String> fieldNames = setters.stream()
  .map(Method::getName)
  .collect(Collectors.toList());

// This will define a "build" method that will invoke the constructor of some object and
// pass in the fields (in order) of the builder to that constructor.
builder = builder
  .define(buildMethod)
  .intercept(MethodCall.construct(constructor)
    .withField(fieldNames.toArray(new String[fieldNames.size()])));
湛铭
2023-03-14

您可以组成两个实现:

FieldAccessor.ofBeanProperty().setsArgumentAt(0).andThen(FixedValue.self());

这将首先设置setters(索引0)参数,然后返回This

如果您想在没有反射的情况下从Method odEnxy设置一个字段,请查看FieldProxy

 类似资料:
  • 问题内容: 我决定使用Java重新创建Snake,但是我有些困惑。目前,我有一个正方形,用户可以使用箭头键在屏幕上移动。当您按一次LEFT时,方型会开始使用计时器向左移动。当您按任何其他已设置的键(向右,向上,向下)时,它会改变方向。我的目标是使用ArrayList容纳组成蛇的正方形。目前,我已经创建了一个ArrayList,其中仅包含一个Snake对象,如果我将第二个Snake对象添加到列表中并

  • 问题内容: 我有在Objective-C中创建和NSAlert的代码,但是现在我想在Swift中创建它。 该警报是为了确认用户要删除文档。 我希望“删除”按钮可以运行删除功能,而“取消”按钮只是为了消除警报。 如何在Swift中编写此代码? 问题答案: 在OS X 10.10 Yosemite中已弃用。 迅捷2 返回或根据用户的选择。 表示添加到对话框的第一个按钮,此处为“确定”。 迅捷3 斯威夫

  • 问题内容: 我尝试使用下面的代码设置Cookie: 我已将角度cookie更新到1.3.14版本,我知道有一个重大更改,但是现在应该如何编写上面的代码? 运行上面的代码,我得到这个错误: 更新:我必须在2个文件中执行此操作: 问题答案: 通过设置变量来实现: 您的版本: 资源 注意: 请记住要包含在您的html中。

  • 我想创建一个Spring Bean Factory后处理器,将Bean添加到当前的ApplicationContext中。 我的中有很多Web-Services定义,我想尽可能地减少。 配置如下所示: 因此,我用以下bean定义创建了一个@Configuration类: 这好多了!,但是我想把它减少得更多,所以我想创建一个名为@WebService定义的注释,并添加一个BeanFactoryPos

  • null 有人能解释一下,当我使用PdfReader阅读模板后,我如何制作模板的副本吗?有没有办法把表格写到模板副本上,而不是一个新文档上? 为了将来的参考,我做了以下工作:

  • 我想展示在我的Java应用程序中,一个人在特定的日期是自由的还是被阻止的。我在Power Point中举了一个我的意图的例子: 提前多谢