可以使用合成或桥接方法来平滑int - >双API变化?

时间:2013-07-02 23:21:51

标签: java minecraft bukkit

Java在名为syntheticbridge的方法上有特殊标记。

  

JLS 13.1.7,“Java编译器引入的任何构造都没有相应的构造   源代码中的构造必须标记为合成 ...“

因此,合成方法是由编译器生成的任何内容,并且未在源代码中表示,虽然在该规范中没有提及PDF,但 bridge 方法用于类型检查泛型。 (例如Animal.interactWith(Creature c)获得一个桥接方法interactWith(Object c),它转换为生物并调用另一种方法。)


我们有一个名为Bukkit的API,它可以提供稳定的访问权限来改变Minecraft服务器的工作方式。我们几乎无法控制的API(也称为vanilla Minecraft)的底层实现的一个方面是,最近在版本1.6.1中强制将其从整数值更改为浮点值。为了避免另一次更改的困难,我们选择将所有API方法更改为double

所以,例如:

public int getHealth();
public void setHealth(int health);
// Must now be
public double getHealth();
public void setHealth(double health);

然而,与往常一样,我们希望使用以前版本1.5.2编译的插件尽可能地工作 - 这就是API的重点。

setHealth是一个已解决的问题,只是引入了一个重载。 目前,我们有一个名为_INVALID_getHealth(V)I的方法,它在实现编译时重命名( API编译)到getHealth(V)I,这样就可以让老插件继续运行。 / p>

但是,当有人试图扩展这些重命名方法的实现时,它们会从双重命名的方法中获得编译错误并覆盖。

有没有办法使用手动/工具插入合成或桥接方法提供intdouble返回,不会导致那些尝试更改部分API实现的人会出现编译错误吗?

2 个答案:

答案 0 :(得分:2)

答案是 - 如果您使用不同的返回类型标记方法,但是使用与composite和bridge相同的参数,则可以编译子类。

在这种特定情况下,创建了一个新的Maven实用程序" Overmapper"来执行此任务,尽管您可以在任何可以编辑Java字节码的自动化工具中执行此操作。这是配置文件:

members:
  "org/bukkit/entity/Damageable _INVALID_damage (I)V": damage
  "org/bukkit/entity/Damageable _INVALID_damage (ILorg/bukkit/entity/Entity;)V": damage
  "org/bukkit/entity/Damageable _INVALID_getHealth ()I": getHealth
  "org/bukkit/entity/Damageable _INVALID_setHealth (I)V": setHealth
  "org/bukkit/entity/Damageable _INVALID_getMaxHealth ()I": getMaxHealth
  "org/bukkit/entity/Damageable _INVALID_setMaxHealth (I)V": setMaxHealth
  "org/bukkit/entity/LivingEntity _INVALID_getLastDamage ()I": getLastDamage
  "org/bukkit/entity/LivingEntity _INVALID_setLastDamage (I)V": setLastDamage
  "org/bukkit/event/entity/EntityDamageEvent _INVALID_getDamage ()I": getDamage
  "org/bukkit/event/entity/EntityDamageEvent _INVALID_setDamage (I)V": setDamage
  "org/bukkit/event/vehicle/VehicleDamageEvent _INVALID_getDamage ()I": getDamage
  "org/bukkit/event/vehicle/VehicleDamageEvent _INVALID_setDamage (I)V": setDamage
  "org/bukkit/event/entity/EntityRegainHealthEvent _INVALID_getAmount ()I": getAmount
  "org/bukkit/event/entity/EntityRegainHealthEvent _INVALID_setAmount (I)V": setAmount
  "org/bukkit/entity/Minecart _INVALID_getDamage ()I": getDamage
  "org/bukkit/entity/Minecart _INVALID_setDamage (I)V": setDamage
  "org/bukkit/entity/Projectile _INVALID_getShooter ()Lorg/bukkit/entity/LivingEntity;": getShooter
  "org/bukkit/entity/Projectile _INVALID_setShooter (Lorg/bukkit/entity/LivingEntity;)V": setShooter
  "org/bukkit/Bukkit _INVALID_getOnlinePlayers ()[Lorg/bukkit/entity/Player;": getOnlinePlayers
  "org/bukkit/Server _INVALID_getOnlinePlayers ()[Lorg/bukkit/entity/Player;": getOnlinePlayers
flags:
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity getHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart getHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity getMaxHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart getMaxHealth ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity setHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart setHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity setMaxHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart setMaxHealth (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity damage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart damage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity damage (ILorg/bukkit/entity/Entity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftEnderDragonPart damage (ILorg/bukkit/entity/Entity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity getLastDamage ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftLivingEntity setLastDamage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftMinecart setDamage (I)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftMinecart getDamage ()I": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftProjectile getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftProjectile setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftArrow getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftArrow setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFireball getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFireball setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFish getShooter ()Lorg/bukkit/entity/LivingEntity;": 0x1001
  "org/bukkit/craftbukkit/v${minecraft_version}/entity/CraftFish setShooter (Lorg/bukkit/entity/LivingEntity;)V": 0x1001

您可以看到所有返回int的方法都被更改为标记为桥接和合成。

答案 1 :(得分:-1)

如果您想对实体运行状况执行某些操作,可以转换为Damageable,然后就不会出现编译错误。

Entity e = /* some entity */;
double health = ((Damageable) e).getHealth();

这应该有效。 我希望它有所帮助