我应该避免使用注释吗?

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

Should I avoid using annotations?

问题

在我的项目中,我从一个 JSON 文件中加载配置(使用 gson),如你所知,缺少的字段将会被填充为空字符串。

其中一些字段是必填的,另一些必须大于 X,我想要对其进行验证。

简单(但不太美观)的方法是为每个属性使用 if 条件,像这样:

if (StringUtils.isEmpty(sftpConfiguration.getHostName)) {
   logger.error("hostName 属性是必填的");
  // 等等。
}

但是,我有多个字段,未来还会添加更多属性,因此我构建了两个注释,分别称为 NorNullEmptyGreaterThen(带有 value 属性),并且我通过以下方式遍历字段:

public static boolean validateWithAnnotation(Object object) throws IllegalAccessException {
	boolean result = true;
	Field[] classFields = object.getClass().getDeclaredFields();

	for (Field field : classFields) {
		if (field.getAnnotation(NorNullEmpty.class) != null) {
			if (field.getType() == String.class) {
				field.setAccessible(true);
				String value = (String) field.get(object);
				if (StringUtils.isEmpty(value)) {
					result = false;
					logger.error("属性 {} 是必填的,但为 null 或空。", field.getName());
				}
				field.setAccessible(false);
			} else {
				logger.warn("@NorNullEmpty 注释仅适用于 String 类型。");
			}
		} else if (field.getAnnotation(GreaterThan.class) != null) {
			Class<?> fieldType = field.getType();
			if (fieldType == long.class || fieldType == Long.class) {
				field.setAccessible(true);
				Long val = field.getLong(object);
				if (val <= field.getAnnotation(GreaterThan.class).value()) {
					result = false;
					logger.error("属性 {} 的值为 {},必须大于 {}。", field.getName(), val, field.getAnnotation(GreaterThan.class).value());
				}
				field.setAccessible(false);
			}
		}
	}

	return result;
}

当我与一位同事进行代码审查时,他对注释的使用感到非常担忧,认为“这是非常冒险和代价昂贵的”。。

我很乐意知道你的想法,我应该使用简单愚蠢的 if 来处理每个字段吗?继续使用反射吗?还是我应该用其他方式验证这些字段?

注:不使用 Spring / Hibernate。

英文:

In my project I’m loading configuration from a json file (using gson) and as you probably know, missing fields will be populate with an empty string.

Some of the fields are mandatory and other must be greater then X, and I want to validate it.

The simple (and ugly) way is to use if condition for each property, like:

if (StringUtils.isEmpty(sftpConfiguration.getHostName)) {
logger.error (“hostName property is mandatory”);
// etc.
}

but, I have more than one field and more and more properties will added in the future, therefore I built two annotations, called NorNullEmpty and GreaterThen (with value property) and I run throw the fields like this:

public static boolean validateWithAnnotation(Object object) throws IllegalAccessException {
boolean result = true;
Field[] classFields = object.getClass().getDeclaredFields();
for (Field field : classFields) {
if (field.getAnnotation(NorNullEmpty.class) != null) {
if (field.getType() == String.class) {
field.setAccessible(true);
String value = (String) field.get(object);
if (StringUtils.isEmpty(value)) {
result = false;
logger.error(&quot;Property {} is mandatory but null or an empty.&quot;, field.getName());
}
field.setAccessible(false);
} else {
logger.warn(&quot;@NorNullEmpty annotation is working on String type only.&quot;);
}
} else if (field.getAnnotation(GreaterThan.class) != null) {
Class&lt;?&gt; fieldType = field.getType();
if (fieldType == long.class || fieldType == Long.class) {
field.setAccessible(true);
Long val = field.getLong(object);
if (val &lt;= field.getAnnotation(GreaterThan.class).value()) {
result = false;
logger.error(&quot;Property {} value is {} and it must be greater than {}.&quot;, field.getName(), val, field.getAnnotation(GreaterThan.class).value());
}
field.setAccessible(false);
}
}
}
return result;
}

When I did a code review with a collage he very afraid from the annotations use, “it’s very risky and very expensive cost”..

I’ll be glad to know what you think, should I use a simple-stupid if for each field? continue with the reflection? or I should validate the fields using other way?

Note: NOT using Spring / Hibernate.

答案1

得分: 3

首先,你正在尝试重新发明轮子。
有一个名为Hibernate Validator的项目,它是Bean验证参考规范的实现。

以下是他们网页上的一个示例:

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

因此,您可以定义验证并运行引擎,它将执行所有检查并在有错误时返回错误。您甚至可以编写自己的验证规则,使其具有可扩展性。

顺便提一下 - 这个项目与Hibernate(在Java世界中广为人知的ORM映射工具)没有任何共同之处。

该项目还与Spring MVC集成,如果您需要类似的功能。

无论如何,它使用了注释方法,确实会带来一些性能损耗。然而,这完全取决于您的数据类型,例如,它仍然比进行网络调用要快得多,所以如果您的项目涉及此类操作,额外的成本可能是可以忽略的。

反射并不像在最初的Java版本中那样慢,但归根结底,您应该尝试并自行判断它是否适合您的需求。否则,我只能猜测。

您可以在这里找到有关这个主题的教程,可能会有所帮助。

英文:

First of all you're trying to re-invent the wheel.
There is a project called Hibernate Validator which is an implementation of the bean validation reference specification.

Here is an example from their landing page:

public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
// ...
}

So you define validations and run the engine, it will perform all the checks and return Errors if there are any. You can even roll your own validations which makes it extensible.

One side-note - this project has nothing common with Hibernate (a well known in the java world ORM mapping tool).

This project also integrates with spring MVC if you need something like that.

Anyway, it does use the annotation approach and it indeed has some performance penalty. However it all depends on what kind of data do you have, for example its still much faster than doing network calls, so if your project does something like that, probably the additional cost will be negligible.

Reflection is not that slow as it used to be in the first Java versions, but bottom line you should try and see yourself whether it fits your needs. Otherwise I can only speculate.

Here you can find a tutorial about this topic, should be relevant

huangapple
  • 本文由 发表于 2020年5月4日 13:07:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/61585524.html
匿名

发表评论

匿名网友

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

确定