Issue
I need to implement the tabulate function (using MenuItem TabulateFunction), which is located in a file with the extension .class in the form of byte-code. Since the function can have one of the three classes that implement my interface, then, according to the task, you need to implement a separate class that will be responsible for reading the byte-code from the file and create an object based on this byte-code.
I made a class ClassLoaderForFunctions and use return defineClass
in it
And here is the problem. When I select Tabulate Function in my menu, it calls the method from ClassLoaderForFunctions which implements the above for the function from the file.
And when it comes to return defineClass
, I get an error: Exception in thread JavaFX Application Thread" java.lang.ClassFormatError: Incompatible magic value 11 in class file tlog/class
In the Main class I call the controller and write the byte code of the tlog
object in a file with the extension .class
*I deleted the import lines for the sake of Stack Trace
What could be the problem?
ClassLoaderForFunctions:
package JavaFX_Application;
public class ClassLoaderForFunctions extends ClassLoader{
public Class<?> loadClassFromFile(File file) throws IOException {
FileInputStream in = new FileInputStream(file);
byte[] fileContent = new byte[in.available()]; //available - возвращает количество байтов ввода, доступные в данный момент для чтения
in.read(fileContent);
in.close();
return defineClass(file.getName(), fileContent, 0, fileContent.length);
}
}
FXMLMainFormController:
package JavaFX_Application;
public class FXMLMainFormController implements Initializable {
public static TabulatedFunctionDoc tabFDoc = new TabulatedFunctionDoc();
private Stage MainStage;
private File file;
private ClassLoaderForFunctions Loader;
private FXMLMenuController ctrl;
private Alert dialog;
@FXML
private MenuItem TabulateFunction;
@FXML
private MenuItem NewFunction;
@FXML
private MenuItem FileClose;
@FXML
private MenuItem OpenFile;
@FXML
private MenuItem SaveFile;
@FXML
private MenuItem SaveFileAs;
@FXML
private TableView<FunctionPointT> table = new TableView<>();
@FXML
private Label point_count;
@FXML
private TextField edX = new TextField(),edY = new TextField();
@FXML
private TableColumn<FunctionPointT,Double> columnX = new TableColumn<FunctionPointT,Double>("X");;
@FXML
private TableColumn<FunctionPointT,Double> columnY = new TableColumn<FunctionPointT,Double>("Y");;
@FXML
private void deletePoint(ActionEvent event) throws IOException {
if (isSelected()) {
tabFDoc.deletePoint(getIndex() - 1);
} else {
if(tabFDoc.getPointsCount() > 2)
tabFDoc.deletePoint(tabFDoc.getPointsCount() - 1);
else
showDialog("Length of Document < 3","Please add some point or stop trying to delete point");
}
}
@FXML
private void addPoint(ActionEvent event) throws InappropriateFunctionPointException, IOException {
if(!edX.getText().isEmpty() && !edY.getText().isEmpty()) {
tabFDoc.addPoint(new FunctionPoint(Double.parseDouble(edX.getText()), Double.parseDouble(edY.getText())));
}
edX.setText("");
edY.setText("");
//table.getItems().add(new FunctionPointT(Double.parseDouble(edX.getText()),Double.parseDouble(edY.getText()))); // добавляем строку
}
@FXML
public void redraw(){
if(!table.getColumns().isEmpty())
table.getItems().clear();
ObservableList<FunctionPointT> data = table.getItems();
for(int i = 0;i< tabFDoc.getPointsCount(); ++ i) {
data.add(new FunctionPointT(tabFDoc.getLink().getPointX(i),tabFDoc.getLink().getPointY(i)));
}
if (isSelected()) {
point_count.setText("Point " + getIndex() + " of " + tabFDoc.getPointsCount());
} else {
point_count.setText("Point " + tabFDoc.getPointsCount() + " of " + tabFDoc.getPointsCount());
}
}
@FXML
private void setSelectedIndexByKey(){
point_count.setText("Point " + getIndex() + " of " + tabFDoc.getPointsCount());
}
@FXML
private void setSelectedIndexByClick() {
if(isSelected() && tabFDoc !=null)
point_count.setText("Point " + getIndex() + " of " + tabFDoc.getPointsCount());
}
private void openWindow() throws IOException {
Stage primaryStage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLMenu.fxml"));
Parent root = loader.load();
ctrl = loader.getController();
ctrl.setMainController(this);
primaryStage.setTitle("Create New Function");
primaryStage.setScene(new Scene(root));
primaryStage.setResizable(false);
primaryStage.initModality(Modality.APPLICATION_MODAL);
primaryStage.initOwner(MainStage);
primaryStage.setOnCloseRequest(windowEvent -> {
windowEvent.consume();
});
primaryStage.showAndWait();
}
private void SaveFunctionAs() throws IOException {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open file");
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Text files", "*.json"));
file = fileChooser.showSaveDialog(table.getScene().getWindow());
if(file!=null) {
tabFDoc.saveFunctionAs(file.getName());
}
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
dialog = new Alert(Alert.AlertType.ERROR);
tabFDoc.setController(this);
columnX.setCellValueFactory(new PropertyValueFactory<FunctionPointT,Double> ("X"));
table.getColumns().add(columnX);
columnY.setCellValueFactory(new PropertyValueFactory<FunctionPointT,Double> ("Y"));
table.getColumns().add(columnY);
table.setPrefWidth(573.0);
table.setPrefHeight(220.0);
columnY.setPrefWidth(286.5);
columnX.setPrefWidth(286.5);
Loader = new ClassLoaderForFunctions();
ObservableList<FunctionPointT> data = table.getItems();
for(int i = 0;i< tabFDoc.getPointsCount(); ++ i) {
data.add(new FunctionPointT(tabFDoc.getLink().getPointX(i),tabFDoc.getLink().getPointY(i)));
}
NewFunction.setOnAction(event -> {
try {
openWindow();
} catch (IOException e) {
e.printStackTrace();
}
});
OpenFile.setOnAction(event ->{
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open file");
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Text files", "*.json"));
file = fileChooser.showOpenDialog(table.getScene().getWindow());
if(file!=null) {
tabFDoc.loadFunction(file.getName());
redraw();
}
});
FileClose.setOnAction(event ->{
MainStage.close();
});
SaveFile.setOnAction(event ->{
try {
tabFDoc.saveFunction();
} catch (IOException e) {
e.printStackTrace();
}
});
SaveFileAs.setOnAction(event -> {
try {
SaveFunctionAs();
} catch (IOException e) {
e.printStackTrace();
}
});
TabulateFunction.setOnAction(event->{
try {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open class");
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Class files", "*.class"));
file = fileChooser.showOpenDialog(table.getScene().getWindow());
//tabFDoc.setFunction((Function) Loader.loadClassFromFile(file).getConstructor().newInstance());
if (file != null) {
openWindow();
if(ctrl.getLeftDomainBorderBorder() != Double.POSITIVE_INFINITY && ctrl.getRightDomainBorderBorder() != Double.NEGATIVE_INFINITY && ctrl.getPointsCount() > 2) {
tabFDoc.tabulateFunction((Function) Loader.loadClassFromFile(file).getConstructor().newInstance(), ctrl.getLeftDomainBorderBorder(), ctrl.getRightDomainBorderBorder(), ctrl.getPointsCount());
redraw();
}
}
}
catch (Exception e) {
}
});
}
public boolean isSelected(){
return (table.getSelectionModel().getSelectedItem() != null);
}
private int getIndex(){
int index = 0;
if (isSelected()) {
for (int i = 0; i < tabFDoc.getPointsCount(); ++i) {
if (table.getSelectionModel().getSelectedItem().getX() == tabFDoc.getLink().getPointX(i) && table.getSelectionModel().getSelectedItem().getY() == tabFDoc.getLink().getPointY(i))
index = i + 1;
}
}
return index++;
}
public void setStage(Stage stage){
MainStage = stage;
}
public Stage getStage(){
return MainStage;
}
public TabulatedFunctionDoc getTabFDoc(){
return tabFDoc;
}
public void showDialog(String header, String message) {
dialog.setHeaderText(header);
dialog.setTitle("Error");
dialog.setContentText(message);
dialog.showAndWait();
}
}
TabulatedFunctionDoc:
package JavaFX_Application;
import functions.*;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class TabulatedFunctionDoc implements TabulatedFunction {
private TabulatedFunction Link;
private String fileName = "";
private boolean modified = false;
private boolean fileNameAssigned = false;
private FXMLMainFormController controller;
private Function function = null;
public TabulatedFunctionDoc() {
Link = new ArrayTabulatedFunction(-1, 1, 2);
}
public void setFunction(Function input_function){
function = input_function;
}
public void setController(FXMLMainFormController ctrl) {
this.controller = ctrl;
}
public void CallRedraw() throws IOException {
if(registerRedrawFunctionController(controller))
controller.redraw();
}
public TabulatedFunction getLink() {
return Link;
}
public boolean registerRedrawFunctionController(FXMLMainFormController ctrl) {
return ctrl.getStage().isShowing();
}
public boolean isModified() {
return modified;
}
public boolean isFileNameAssigned() {
return fileNameAssigned;
}
public void newFunction(double leftX, double rightX, int pointsCount) throws IOException {
Link = new ArrayTabulatedFunction(leftX, rightX, pointsCount);
modified = false;
}
public void tabulateFunction(Function function, double leftX, double rightX, int pointsCount) {
Link = TabulatedFunctions.tabulate(function, leftX, rightX, pointsCount);
modified = false;
}
public void saveFunctionAs(String fileName) throws IOException {
this.fileName = fileName;
fileNameAssigned = true;
saveFunction();
modified = false;
}
public void loadFunction(String fileName) {
this.fileName = fileName;
fileNameAssigned = true;
JSONParser jsonParser = new JSONParser();
try (FileReader reader = new FileReader(fileName))
{
Object obj = jsonParser.parse(reader);
JSONArray employeeList = (JSONArray) obj;
FunctionPoint[] array = new FunctionPoint[employeeList.size()];
//System.out.println(employeeList);
for(int i = 0; i < employeeList.size(); ++ i){
JSONObject employeeObject = (JSONObject)((JSONObject)employeeList.get(i)).get("Точки");
array[i] = new FunctionPoint((Double) employeeObject.get("X"),(Double) employeeObject.get("Y"));
}
this.Link = new ArrayTabulatedFunction(array);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
modified = false;
}
public void saveFunction() throws IOException {
JSONArray Link = new JSONArray();
for(int i =0; i < this.Link.getPointsCount(); ++i){
JSONObject point = new JSONObject();
point.put("X",this.Link.getPointX(i));
point.put("Y",this.Link.getPointY(i));
JSONObject points = new JSONObject();
points.put("Точки",point);
Link.add(points);
}
FileWriter fileWriter = new FileWriter(fileName);
fileWriter.write(Link.toJSONString());
fileWriter.flush();
modified = false;
}
@Override
public int getPointsCount() {
return this.Link.getPointsCount();
}
@Override
public void setPointY(int index, double y) throws IOException {
this.Link.setPointY(index, y);
this.modified = true;
CallRedraw();
}
@Override
public double getPointY(int index) {
return this.Link.getPointY(index);
}
@Override
public double getPointX(int index) {
return this.Link.getPointX(index);
}
@Override
public double getFunctionValue(double x) {
return this.Link.getFunctionValue(x);
}
@Override
public void addPoint(FunctionPoint point) throws InappropriateFunctionPointException, IOException {
this.modified = true;
this.Link.addPoint(point);
CallRedraw();
}
@Override
public void setPoint(int index, FunctionPoint point) throws InappropriateFunctionPointException, IOException {
this.Link.setPoint(index, point);
this.modified = true;
CallRedraw();
}
@Override
public void setPointX(int index, double x) throws InappropriateFunctionPointException, IOException {
this.Link.setPointX(index, x);
this.modified = true;
CallRedraw();
}
@Override
public void deletePoint(int index) throws IOException {
this.Link.deletePoint(index);
this.modified = true;
CallRedraw();
}
@Override
public double getRightDomainBorder() {
return this.Link.getRightDomainBorder();
}
@Override
public double getLeftDomainBorder() {
return this.Link.getLeftDomainBorder();
}
@Override
public FunctionPoint getPoint(int index) {
if (index >= 0 && index < this.getPointsCount()) {
return new FunctionPoint(this.Link.getPoint(index));
} else {
throw new FunctionPointIndexOutOfBoundsException();
}
}
}
Stack Trace:
Exception in thread "JavaFX Application Thread" java.lang.ClassFormatError: Incompatible magic value 11 in class file tlog/class
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1010)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:872)
at JavaFX_Application.ClassLoaderForFunctions.loadClassFromFile(ClassLoaderForFunctions.java:15)
at JavaFX_Application.FXMLMainFormController.lambda$initialize$6(FXMLMainFormController.java:206)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.controls/javafx.scene.control.MenuItem.fire(MenuItem.java:459)
at javafx.controls/com.sun.javafx.scene.control.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1385)
at javafx.controls/com.sun.javafx.scene.control.ContextMenuContent$MenuItemContainer.lambda$createChildren$12(ContextMenuContent.java:1338)
at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3897)
at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1878)
at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2623)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449)
at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:557)
at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:943)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:831)
Solution
What you are apparently trying to do is generate a .class
file that you can then load.
But the problem is that what you are actually writing to "tlog.class" is not in the standard class file format. In fact, it looks like you are just writing a bunch of numbers using DataOutputStream
methods. That isn't even remotely close to valid1.
At any rate, when you then attempt to load the (supposed) class file, the JVM is saying, in effect:
"Nah! That's not in a valid class file format. It doesn't even start with the correct magic number!"
So what is the solution?
Well you could (in theory) generate a valid class file. The problem is that creating a valid class file that implements your function is going to be difficult, and require deep knowledge of Java bytecodes and the structure of class files. And it is not clear that you are going to achieve anything by doing that.
Here are a couple of (probably) better ideas.
Just read and write the data as a data file. Then write some Java code that implements the required function, using the data that you read from the file.
Write some Java code to generate Java source code for the function, embedding the data in the file as arrays of constants or whatever. Then call the Java compiler to compile it, and load the resulting
.class
file.
The first option is the simplest, and most likely all that you need. You might consider the second option if the function was performance critical. But you should only do that if you have measured the performance. Besides, you will probably find the the speedup will be small, and not worth the considerable effort needed to achieve it.
1 - The format is documented in Chapter 4 of the JVM specification. You will need to understand a lot more of the spec in order to write the bytecodes for the classes methods and pseudo-methods.
Answered By - Stephen C
Answer Checked By - David Goodson (JavaFixing Volunteer)