Java注释和处理器将方法标记为只能调用一次且仅一次?
我需要能够标记方法,以便在多次调用它们时抛出 RuntimeException。
我正在尝试强制执行一些单一赋值语义,并且我的类的参数数量太大,无法放入单个构造函数中,并且我需要能够使这些类 JAXB
也知道,因此对象需要是可变的,但我想强制执行单一赋值语义。
我很确定我可以使用 Aspects 来做到这一点,但我真的希望能够使用我自己的注释处理器。
我知道如何使用 Python 中的装饰器来做到这一点。
如何编写一个注释处理器,它可以在运行时拦截对带注释方法的调用,而不仅仅是在编译时?
我想我正在使用动态代理拦截方法调用,我只需要了解如何将它们与我的注释处理器集成。
动态代理要求您使用接口,这很麻烦,我有一个 CGLib MethodInterceptor 现在正在工作,对拦截内容的要求要少得多装饰,以添加依赖项为代价。
I need to be able to mark methods so that they throw a RuntimeException if they are called more than once.
I am trying to enforce some single assignment semantics and the number of parameters to my class is too large to put in a single constructor and I need to be able to make these classes JAXB
aware as well, so the objects need to be mutable but I want to enforce single assignment semantics.
I am pretty sure I can do this with Aspects, but I would really like to be able to use my own Annotations processor instead.
I know how to do this with Decorators in Python.
How do I write an Annotation processor that can intercept calls to the annotated method at runtime and not just at compile time?
I think I am on to something with with Dynamic Proxies intercepting the method calls, I just need to figure out how to integrate them with my Annotation processor.
Dynamic Proxies require you to use an Interface, that is way to cumbersome, I have a CGLib MethodInterceptor working now, much less requirements on what gets intercepted and decorated, at the expense of adding a dependency.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不,没有任何现成可用的东西。 AspectJ 似乎是使其以更通用的方式工作的唯一方法。正如 JB Nizet 所指出的 - 注释应该有一个解析器来解析它。
但是,我建议使用更好、更简单的解决方案 - Builder 模式。它看起来像什么:
FooBuilder
(它也可能是一个静态内部类),它是可变的,并且为FooBuilder
的 返回Foo
实例的build()
方法Foo
有一个仅接受FooBuilder
的构造函数,并且您在那里分配每个字段。这样:
Foo
是不可变的,这是您的最终目标它很容易使用。您只需设置您需要的字段。像这样的东西:
这样构建器就可以感知 JAXB。例如:
JAXB对象需要是可变的,而您的要求是不可变的对象。因此,构建器可以方便地弥补这一点。
Nope, there's nothing ready-to-use. And AspectJ seems the only way to make it work in a more general manner. As JB Nizet noted - the annotation should have a parser to parse it.
However, I would advise for a better and simpler solution - the Builder pattern. What does it look like:
FooBuilder
(it may also be a static inner class) which is mutable and has a setter and getter for each of the fieldsFooBuilder
has abuild()
method that returns an instance ofFoo
Foo
has a constructor that takes onlyFooBuilder
, and you assign each field there.That way:
Foo
is immutable, which is your end goalIt is easy to use. You only set the fields that you need. Something like:
That way the builder can be JAXB-aware. For example:
JAXB objects need to be mutable, and your requirement is an immutable object. Hence the builder comes handy to bridge that.
这个问题与问题Applying CGLib Proxy from a Annotation Processor有一些相似之处。
如果您希望能够更改注释处理器中原始源代码的行为,请查看 http://projectlombok .org/ 实现了这一点。 IMO 唯一的缺点是 lombok 依赖 com.sun.* 类。
由于我自己需要这种东西,我想知道是否有人知道更好的方法来实现这一点,仍然使用注释处理器。
This question shows some resemblance with question Applying CGLib Proxy from a Annotation Processor.
If you want to be able to change the behavior of the original source code in an annotation processor have a look at how http://projectlombok.org/ achieves this. The only downside IMO is that lombok relies on com.sun.* classes.
Since I need this kind of stuff myself I wonder if someone knows of a better way to achieve this, still using annotation processors.
您可以使用
@XmlAccessorType(XmlAccessType.FIELD)
将 JAXB 配置为使用字段(实例变量)访问。这将允许您使用 set 方法执行所需的操作:您还可以使用 JAXB 的
XmlAdapter
支持不可变对象的机制:You can configure JAXB to use field (instance variable) access using
@XmlAccessorType(XmlAccessType.FIELD)
. This will allow you to do what you need to with the set method:You can also use JAXB's
XmlAdapter
mechanism to support immutable objects:您可以使用注释来代替。
每种方法都需要一个计数器。
Instead of using an annotation you can use.
You would need one counter per method.
我有类似的要求。长话短说,当您在 Spring 中注入组件时,像 A 依赖于 B 且 B 依赖于 A 这样的循环依赖情况完全没问题,但是您需要将这些组件作为字段或 setter 注入。构造函数注入会导致堆栈溢出。因此,我必须为这些组件引入一个方法
init()
,与构造函数不同,该方法可能会被错误调用多次。不用说,像这样的样板代码开始到处出现。由于这远不是应用程序的关键点,因此我决定引入一种优雅的线程安全单行解决方案,注重简洁而不是速度:
现在,因为我更喜欢在 DI 中构建应用程序在框架中,将 Guard 声明为组件,然后注入它,并调用实例方法 requireCalledOnce 听起来很自然。但由于其普遍的风格,静态参考产生了更多的意义。现在我的代码如下所示:
这是第二次调用同一对象的
init
时出现的异常:I had a similar requirement. Long story short when you inject components in Spring the cyclic dependency situation like A depends on B and B depends on A is perfectly fine, but you need to inject these components as fields or setters. Constructor injection causes a stack overflow. Therefore I had to introduce a method
init()
for these components, which unlike constructors might be erroneously called more than once. Needless to say boilerplate code like:started to emerge everywhere. Since this is nowhere close to being a critical spot of the application, I made a decision to introduce an elegant thread-safe one-liner solution favoring conciseness over speed:
Now, since I prefer building applications within DI frameworks it might sound natural to declare
Guard
as a component, then inject it, and call an instance methodrequireCalledOnce
instead. But due to its universal flavor, static reference yields more sense. Now my code looks like this:and here is an exception upon the second invocation of
init
of the same object: