В настоящее время я работаю над плагином Bukkit для Minecraft и получаю ошибку java .lang.InstantiationError при попытке создать новый объект. Трассировка стека выглядит следующим образом:
Caused by: java.lang.InstantiationError: fancyui.craterhater.components.FancyComponent
at fancyui.craterhater.uibuilder.ComponentMaker.getComponent(ComponentMaker.java:13) ~[?:?]
at fancyui.craterhater.uibuilder.Editor_Page_0.getComponents(Editor_Page_0.java:40) ~[?:?]
at fancyui.craterhater.uibuilder.Editor$1.call(Editor.java:36) ~[?:?]
at fancyui.craterhater.masterfancyui.FancyUI.openInventory(FancyUI.java:195) ~[?:?]
at fancyui.craterhater.uibuilder.Editor.createEditorGUI(Editor.java:236) ~[?:?]
at fancyui.craterhater.commandhandler.MasterCommand$2.call(MasterCommand.java:69) ~[?:?]
at fancyui.craterhater.commandhandler.CECommand.playerExecutes(CECommand.java:105) ~[?:?]
at fancyui.craterhater.commandhandler.CECommand.checkPlayerExecutes(CECommand.java:98) ~[?:?]
at fancyui.craterhater.commandhandler.MasterCommand.onCommand(MasterCommand.java:153) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[1.8.jar:git-Spigot-870264a-0a645a2]
... 15 more
В строке 13 класса ComponentMaker просто говорится:
FancyComponent fancyComponent = new FancyComponent();
Я провел некоторую отладку и решил напечатать следующее:
System.out.println(FancyComponent.class.toGenericString());
Это напечатано;
public abstract class fancyui.craterhater.components.FancyComponent
Пока класс FancyComponent не является абстрактным. Вот класс FancyComponent:
public class FancyComponent {
//FancyComponent class represents the individual items placed in a FancyUI.
//It handles things such as animation, itemstack building and event handling whilst
//allowing the FancyUI to handle loading and deleting of these components.
//FancyComponents are added to the FancyUI by the user of the API using LoadFunctions.
//They can also be generated from a FancyUI file.
private FancyLocation fancyLocation;
private FancyItemStack fancyItemStack;
private FancyDisplayType fancyDisplayType;
private String identifier = null;
private int ID = 0;
private int basicSlot = 0;
private boolean copied;
public FancyComponent() {
fancyDisplayType = FancyDisplayType.DYNAMIC;
}
public FancyComponent copy(FancyLocation newLocation) {
FancyComponent newComponent = new FancyComponent();
newComponent.setDisplayType(fancyDisplayType);
newComponent.setID(ID);
newComponent.setFancyItemStack(fancyItemStack);
newComponent.setFancyLocation(newLocation);
newComponent.setAttributes(attributes);
newComponent.setIdentifier(identifier);
return newComponent;
}
//Method gets called when FancyUI decides to load in new FancyComponents.
//This happens when openInventory gets called and new components are generated.
//This method should start future animations. It should also handle ItemStack placement.
//The boolean here represents whether or not it has succesfully been added. This is used in the
//FancyUI in order to keep track of all active components and not the once off-screen.
public boolean addToUI(Inventory inventory, Player p, FileConfiguration fc, FileConfiguration fc2) {
if(fancyLocation == null) {return false;}
return addToUI(inventory, p, fancyLocation, fc, fc2);
}
public boolean addToUI(Inventory inventory, Player p, FancyLocation fancyLocation, FileConfiguration fc, FileConfiguration fc2) {
if(fancyItemStack == null) {return false;}
FancyUI fancyUI = fancyLocation.getFancyUI();
FancyLocation masterFancyLocation = fancyUI.getFancyData().getCurrentFancyLocation();
if(!fancyLocation.isInView(masterFancyLocation, fancyDisplayType)) {return false;}
int basicSlot = fancyLocation.getBasicLocation(masterFancyLocation.getX(), masterFancyLocation.getY(), fancyDisplayType);
if(basicSlot < 0 || basicSlot >= inventory.getSize()) {return false;}
this.basicSlot = basicSlot;
ItemStack itemStack = fancyItemStack.buildItemStack(p,fc2);
if(fc != null) {
if(fc.contains("Components."+identifier+".Animations")) {
for(String animation : fc.getConfigurationSection("Components."+identifier+".Animations").getKeys(false)) {
if(fc.getBoolean(("Components."+identifier+".Animations."+animation+".continious"))){
List<String> frames = new ArrayList<>();
if(fc.contains("Components."+identifier+".Animations."+animation+".animation")) {
frames = fc.getStringList("Components."+identifier+".Animations."+animation+".animation");
}
int interval = fc.getInt("Components."+identifier+".Animations."+animation+".interval");
if(interval < 1) {
interval = 2;
}
int position = fc.getInt("Components."+identifier+".Animations."+animation+".position");
boolean continious = fc.getBoolean("Components."+identifier+".Animations."+animation+".continious");
boolean reverse = fc.getBoolean("Components."+identifier+".Animations."+animation+".reverse");
fancyItemStack.startAnimation(frames, p, interval, position, this, continious, reverse);
break;
}
}
}
}
if(fancyLocation.getFancyUI().getFancyData().isPlayerInventory()) {
if(fancyItemStack.getCustomName().getFancyStringAnimations().length > 0) {
fancyItemStack.startAnimation(fancyItemStack.getCustomName().getFancyStringAnimations()[0].getFrames(), p, 4, 0, this, true, false);
}
}
inventory.setItem(basicSlot, itemStack);
return true;
}
//Method to reload just this component. It is used when cycling through fancyLore. If a function makes changes
//to other components the reload method in the FancyUI has to be called in order to fully reload a page.
public void reload(Player p) {
FileConfiguration fc = DataHandler.getFile(96,p.getUniqueId().toString(), false, "Data", "Users");
ItemStack itemStack = fancyItemStack.buildItemStack(p,fc);
if(fancyLocation == null) {
return;
}
if(fancyLocation.getFancyUI().getFancyData().isPlayerInventory()) {
p.getInventory().setItem(basicSlot, itemStack);
return;
}
fancyLocation.getFancyUI().getFancyData().getInventory().setItem(basicSlot, itemStack);
}
//Method gets called when FancyUI deletes all information on other FancyComponents.
//This happens when openInventory gets called and new components are generated.
//Make sure that this method cleans up future animations so they don't go around throwing nullpointers.
//The ItemStack itself is removed automatically by the FancyUI.
public void notifyOfDeletion() {
fancyItemStack.stopAnimating();
}
//Attributes are pieces of code written by the user of the API in order to have certain things
//happen at certain events such as ON_CLICK or ON_DROP etc.
private List<Attribute> attributes = new ArrayList<>();
public void addAttribute(Attribute attribute) {
attributes.add(attribute);
}
public List<Attribute> getAttributes(){
return attributes;
}
public void setAttributes(List<Attribute> attributes) {
this.attributes = attributes;
}
//Method to identify which Attributes need to run at these specific occasions. These occasions
//may include things suchs as ON_CLICK or ON_1 just to name a few. This method consists of two
//distinct parts. The first part handles all generated components which have scripts assigned to them
//and the second part handles all components that have been generated by the plugin itself. And thus
//do not have scripts assigned to them.
public void handleEvent(FileConfiguration fc, FileConfiguration fc2, FunctionParams params, AttributeOccasion... attributeOccasions) {
//The 'identifier' is a tag all generated components get. It is unique to all components.
//Non-generated components do not have this tag and thus we can check for null to see whether or not
//it is generated.
if(identifier != null) {
if(fc.contains("Components."+identifier+".Scripts")) {
for(String script : fc.getConfigurationSection("Components."+identifier+".Scripts").getKeys(false)) {
if(fc.contains("Components."+identifier+".Scripts."+script+".events")) {
List<String> scriptLines = fc.getStringList("Components."+identifier+".Scripts."+script+".script");
for(String event : fc.getStringList("Components."+identifier+".Scripts."+script+".events")) {
A: for(AttributeOccasion attributeOccasion : attributeOccasions) {
if(attributeOccasion.name().equalsIgnoreCase(event)) {
fancyLocation.getFancyUI().getScriptParser().executeScript(params.getPlayer(), scriptLines, FancyUI.fancyUI.get(params.getPlayer().getUniqueId()), params.getFancyComponent(), fc2, false);
break A;
}
}
}
}
}
}
if(fc.contains("Components."+identifier+".Animations")) {
for(String script : fc.getConfigurationSection("Components."+identifier+".Animations").getKeys(false)) {
if(fc.contains("Components."+identifier+".Animations."+script+".events")) {
for(String event : fc.getStringList("Components."+identifier+".Animations."+script+".events")) {
A: for(AttributeOccasion attributeOccasion : attributeOccasions) {
if(attributeOccasion.name().equalsIgnoreCase(event)) {
List<String> frames = new ArrayList<>();
if(fc.contains("Components."+identifier+".Animations."+script+".animation")) {
frames = fc.getStringList("Components."+identifier+".Animations."+script+".animation");
}
int interval = fc.getInt("Components."+identifier+".Animations."+script+".interval");
if(interval < 1) {
interval = 2;
}
int position = fc.getInt("Components."+identifier+".Animations."+script+".position");
boolean continious = fc.getBoolean("Components."+identifier+".Animations."+script+".continious");
boolean reverse = fc.getBoolean("Components."+identifier+".Animations."+script+".reverse");
fancyItemStack.startAnimation(frames, params.getPlayer(), interval, position, this, continious, reverse);
break A;
}
}
}
}
}
}
}
//Handles all components generated by the plugin as well as generated components from file if this component is inside of an editor.
//If inside an editor generated components will have some attributes linked to them by the plugin. If not inside an editor, generated components
//will not have any attributes linked to them.
A:for(Attribute attribute : attributes) {
for(AttributeOccasion attributeOccasion : attribute.getAttributeOccasions()){
for(AttributeOccasion attributeOccasion2 : attributeOccasions) {
if(attributeOccasion.equals(attributeOccasion2)) {
attribute.getAttributeFunction().call(params);
continue A;
}
}
}
}
}
//This method is used to move the cursor in list cycleables.
public void performCursorMove(int delta, Player p) {
if(fancyItemStack == null) {return;}
FancyLore fancyLore = fancyItemStack.getFancyLore();
if(fancyLore == null) {return;}
fancyLore.moveCursor(delta, p);
}
public void setCursorPosition(int n, Player p) {
if(fancyItemStack == null) {return;}
FancyLore fancyLore = fancyItemStack.getFancyLore();
if(fancyLore == null) {return;}
fancyLore.setCursorPosition(n, p);
}
public int getSlot() {
return basicSlot;
}
public FancyLocation getFancyLocation() {
return fancyLocation;
}
public FancyItemStack getFancyItemStack() {
return fancyItemStack;
}
public void setFancyItemStack(FancyItemStack fancyItemStack) {
this.fancyItemStack = fancyItemStack;
}
public void setFancyLocation(FancyLocation fancyLocation) {
this.fancyLocation = fancyLocation;
}
public void setDisplayType(FancyDisplayType fancyDisplayType) {
this.fancyDisplayType = fancyDisplayType;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return identifier;
}
public void setIsCopied(boolean copied) {
this.copied = copied;
}
public boolean isCopied() {
return copied;
}
public void setID(int ID) {
this.ID = ID;
}
public int getID() {
return ID;
}
public FancyDisplayType getFancyDisplayType() {
return fancyDisplayType;
}
}
Странно то, что это не происходит в более поздних версиях Spigot. Я проверил это на 1.8, 1.9 и 1.15, и ошибка происходит на 1.8 и 1.9, но не на 1.15. Любая помощь будет оценена.
Похоже, только не выдает ошибку в последней версии (1.15). Все остальные версии выдают ошибку.
После нескольких часов тестирования я решил скопировать и вставить код проблемного c класса в новый класс. Я переименовал все ссылки на этот класс. Это исправило мою проблему, но я не особенно доволен ею, тем более что оригинальное имя все еще вызывает ошибку. Поэтому, если я переименую новый класс в старое имя, снова появится ошибка.