Maison >Java >javaDidacticiel >Les annotations les plus maléfiques de Java
Cet article a été initialement traduit par MaNong.com – Sun Tenghao Veuillez lire les exigences de réimpression à la fin de l'article pour la réimpression. Bienvenue pour participer à notre plan de contribution payante.
Lorsque Java 1.5 a introduit les annotations, les développeurs d'entreprise avaient de grandes attentes pour simplifier le développement d'EJB et d'autres produits d'entreprise. Vous pouvez consulter un article de la même période Simplifier le développement Java d'entreprise avec EJB 3.0.
Cependant, depuis lors, l'utilisation d'annotations dans les entreprises Java a eu des conséquences et des effets secondaires imprévus, dont certains n'ont même pas été remarqués aujourd'hui. Heureusement, tous les effets secondaires ne passent pas inaperçus. Pour regarder quelques exemples, il existe de nombreux commentaires précieux sur StackOverflow intitulés « Pourquoi les annotations Java ? » et cet article « Les annotations sont-elles mauvaises » et « Magics Is Evil ? » » « Annotations… bonnes, mauvaises ou pires ? »
Bien que la plupart des discussions ci-dessus contiennent des points précieux, toutes les annotations ne sont pas identiques. le même.
Il existe deux types d'annotations, la différence réside dans leur impact sur le programme pendant l'exécution. Parlons d’abord des éléments inoffensifs, qui n’auront aucun impact sur le code à l’exécution ; l’autre concerne les éléments nuisibles, qui modifieront le comportement d’exécution. Les annotations inoffensives incluent @Deprecated, @Override, @SuppressWarnings, etc. Les annotations nuisibles incluent @Entity, @Table, @PostConstruct, @ApplicationScoped, etc.
Il existe un petit ensemble d'annotations parmi les annotations inoffensives qui sont très utiles. Certains permettent de détecter les erreurs lors de la compilation (vérification statique) ou apportent des garanties de sécurité. Certaines annotations utiles incluent : @Override, @NonNull/@Nullable from (Checker Framework), etc.
Nous avons défini quelques annotations nuisibles, pourquoi devrions-nous éviter de les utiliser ?
Imaginez une classe Java Data standard avec une méthode @PostConstruct. Cette annotation indique que la méthode annotée doit être appelée après la création de l'objet. Cette fonctionnalité n'est pas gérée par la JVM, donc la classe Date obtient implicitement des frames et des conteneurs inconnus sans rien faire sémantiquement. Que se passe-t-il si ce code ne s'exécute dans aucun conteneur, mais uniquement dans la JVM ? Cette annotation réduit considérablement la réutilisabilité de cette classe. De plus, les tests unitaires partout où Date est utilisé deviennent un cauchemar, car vous devez vous assurer que la post-construction est correctement liée à chaque fois et qu'un conteneur compatible doit être simulé. C'est un peu ridicule, une classe Date a besoin d'un conteneur pour s'exécuter, mais c'est bien l'impact néfaste des annotations sur les classes, les méthodes et les paramètres.
Il est indéniable que la logique métier est souvent complexe et nécessite plus de dépendances et de relations qu'une simple classe Date. Cependant, il n'y a aucune raison d'ajouter explicitement ou implicitement des dépendances ou des contraintes inutiles à une classe. Les annotations nuisibles ne sont que cela : des dépendances et des contraintes.
Malheureusement, des allégations préjudiciables sont légitimées dans Java Enterprise 5 à grande échelle. Pour corriger les premiers problèmes d'utilisabilité des API d'entreprise, des annotations ont été utilisées pour masquer les parties redondantes et difficiles à utiliser du système. Le nouveau JEE 5 a été salué comme étant « léger » et « simple », et cela semble l'être à première vue. Mais un abus minime, mais crucial, s’est propagé.
@Stateless public class DocumentRepository { public Document getDocument(String title) { ... } ... }
Si vous souhaitez obtenir un EJB Stateless, il vous suffit de déclarer l'annotation @Stateless sur la classe. En effet, l'écriture de cette classe ne nécessite que quelques clics, mais veuillez noter que les annotations nuisibles de cette classe sont liées à des centaines de pages de documentation et ne fonctionneront que sur un serveur d'applications d'un mégaoctet. Comment peut-on qualifier cela de « léger » ? Par conséquent, cette annotation n'est qu'un espace réservé pour le code Java qui doit réellement être écrit, et le code doit toujours exister sous une forme ou une autre. Maintenant, c'est juste caché sous les annotations.
Malheureusement, cette solution de contournement est connue sous le nom de modèle et les annotations nuisibles sont désormais largement diffusées : JPA, CDI, Common Annotations, JAXB, etc.
Étant donné que les annotations sont souvent utilisées comme environnement de développement, les annotations nuisibles sont parfois traitées comme un principe de responsabilité unique (principe de responsabilité unique) ou Meilleures pratiques pour la séparation des préoccupations.
Considérons l'exemple CDI suivant :
@ApplicationScoped public class DocumentFormatter { ... }
L'annotation ci-dessus décrit que cette classe doit être un bean CDI, ce qui signifie qu'elle doit ne peut être instancié que par CDI, garantissant une seule instance par application.
Ces messages n'appartiennent pas à cette catégorie. Ce service n'a aucun impact fonctionnel (de quelque manière que ce soit) sur son rôle dans l'application actuelle. Il y a ici deux préoccupations évidentes.
Un exemple simple de JPA :
@Entity @Table("PERSON") public class Person { ... }
问题在于这种类往往是”领域对象(domain objects)”,它们直接将领域模型持久化。更糟的是,数据传送对象(DTO)用来在对象之间传送数据,使得整个构造变得脆弱,因为对象间耦合过于紧密。不管怎样,这是一种错误的方式。
所有的这些附加的功能和(或)信息应该从这些类中分离出来,但是它们却悄悄混在一起,因为它们”只不过”是注解。
注解有时会传染其他对象。回顾上面那个CDI Bean。每个使用它的对象,每个依赖它的对象现在都拥有一个CDI注解,否则依赖关系树就不会构建成功。
@Entity注解也一样。因为对象之间的关系,其他对象也通过注解持久化,很快所有的持久化对象都会有这个注解。我们无法使用原生的第三方对象(除非序列化或包装它们),我们无法使用其他持久化机制(比如用NoSQL DB存放对象)。
这些注解使得这些对象无法复用。它们只能在一个严格的、受控制的、不透明的环境中使用,不能和任何东西整合。
是XML吗?当然不是,至少对于上面的例子来说不是。
Spring框架使用配置来管理对象,因此可以用XML当做配置文件。然而,是否某个依赖需要在运行期改变,而不通过重新编译?如果不需要,那么很难说配置应该用另一门语言来表示,尤其重构困难、测试困难、管理需要特殊工具。
真正的替代品当然是好的Java代码,正确封装并解耦的。是的,用代码来管理对象,尽管有时被当做样板(boilerplate),但并不算糟糕。它带来一些好处,比如让代码可读、可调试、可重构。只有那些长片的、复杂的、冗余的样板是糟糕的,比如“关于EJB 2.0”。但是解决方案并不是摆脱所有的样板或用另一种语言隐藏样板,而是简单干净的架构,直接而不多余的信息,简单并合适的方式来面向对象。
这也适用于JPA、Spring和其他东西。误用注解来表示功能会发生Stcakoverflow上这个问题“Arguments Against Annotations”,为什么不用已有的工具呢:比如Java语言本身和编译器,来解决这类问题,面向对象和软件最佳实践。
如果注解在代码运行期加上了额外功能和约束,那它是有害的。这很糟糕,因为它隐藏了类或方法的切面,使之难懂、难复用、难重构、难测试。
不幸的是Java Enterprise不理睬Java开发者社区中发对注解的声音。所以企业级Java和其他”官方”框架更不可能重视这类问题。
至少我们可以持续关注有害的注解,如果可能尽量避免使用,编写新的框架和软件替换掉注解,不会出现有害注解所带来的问题。
以上就是Java中万恶的注解 的内容,更多相关内容请关注PHP中文网(www.php.cn)!