Skip to content

Revert remove blender#709

Open
neph1 wants to merge 3 commits into
jMonkeyEngine:masterfrom
neph1:revert-remove-blender
Open

Revert remove blender#709
neph1 wants to merge 3 commits into
jMonkeyEngine:masterfrom
neph1:revert-remove-blender

Conversation

@neph1

@neph1 neph1 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Short term fix

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the jme3-blender module to add GLTF support to the jMonkeyEngine SDK, including NetBeans project configurations, a GLTF data object handler, and Python scripts for importing external models via Blender. The code review identified several critical issues: potential resource leaks in Scripts.java and OutputReader.java due to unclosed streams, a potential NameError in the Python scripts if file operations fail, potential NullPointerExceptions in GLTFDataObject.java and GltfExtrasLoader.java, and an inefficient exception-based control flow in GltfExtrasLoader.java that should be replaced with proper JSON type checks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +41 to +63
try {
InputStream in = null;
OutputStream out = null;
try {
URL url = URI.create("nbres:" + root + name).toURL();
file = FileUtil.createData(folder, name);
in = url.openStream();
out = file.getOutputStream();
FileUtil.copy(in, out);
} catch (IOException e) {
Exceptions.printStackTrace(e);
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
logger.log(Level.INFO, "Extracted script {0}", file.getPath());
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If in.close() throws an IOException in the finally block, out.close() will be skipped, causing a resource leak. Since the project uses Java 21, we should use try-with-resources to automatically and safely manage both streams.

            try {
                URL url = URI.create("nbres:" + root + name).toURL();
                file = FileUtil.createData(folder, name);
                try (InputStream in = url.openStream();
                     OutputStream out = file.getOutputStream()) {
                    FileUtil.copy(in, out);
                }
                logger.log(Level.INFO, "Extracted script {0}", file.getPath());
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }

Comment on lines +26 to +40
def save_file(save_path):
# Check if output file exists already
try:
f = open(save_path, 'w')
f.close()
ok = True
except:
print("Cannot save to path %r" % save_path)

import traceback
traceback.print_exc()

# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If an exception occurs when opening the file, ok is never defined, which will cause a NameError: name 'ok' is not defined when if ok: is evaluated. We should initialize ok = False beforehand. Also, using a with statement is more idiomatic and avoids bare except: clauses per PEP 8.

Suggested change
def save_file(save_path):
# Check if output file exists already
try:
f = open(save_path, 'w')
f.close()
ok = True
except:
print("Cannot save to path %r" % save_path)
import traceback
traceback.print_exc()
# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)
def save_file(save_path):
# Check if output file exists already
ok = False
try:
with open(save_path, 'w') as f:
pass
ok = True
except Exception:
print("Cannot save to path %r" % save_path)
import traceback
traceback.print_exc()
# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)

Comment on lines +26 to +40
def save_file(save_path):
# Check if output file exists already
try:
f = open(save_path, 'w')
f.close()
ok = True
except:
print("Cannot save to path %r" % save_path)

import traceback
traceback.print_exc()

# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If an exception occurs when opening the file, ok is never defined, which will cause a NameError: name 'ok' is not defined when if ok: is evaluated. We should initialize ok = False beforehand. Also, using a with statement is more idiomatic and avoids bare except: clauses per PEP 8.

Suggested change
def save_file(save_path):
# Check if output file exists already
try:
f = open(save_path, 'w')
f.close()
ok = True
except:
print("Cannot save to path %r" % save_path)
import traceback
traceback.print_exc()
# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)
def save_file(save_path):
# Check if output file exists already
ok = False
try:
with open(save_path, 'w') as f:
pass
ok = True
except Exception:
print("Cannot save to path %r" % save_path)
import traceback
traceback.print_exc()
# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)

Comment on lines +26 to +40
def save_file(save_path):
# Check if output file exists already
try:
f = open(save_path, 'w')
f.close()
ok = True
except:
print("Cannot save to path %r" % save_path)

import traceback
traceback.print_exc()

# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If an exception occurs when opening the file, ok is never defined, which will cause a NameError: name 'ok' is not defined when if ok: is evaluated. We should initialize ok = False beforehand. Also, using a with statement is more idiomatic and avoids bare except: clauses per PEP 8.

Suggested change
def save_file(save_path):
# Check if output file exists already
try:
f = open(save_path, 'w')
f.close()
ok = True
except:
print("Cannot save to path %r" % save_path)
import traceback
traceback.print_exc()
# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)
def save_file(save_path):
# Check if output file exists already
ok = False
try:
with open(save_path, 'w') as f:
pass
ok = True
except Exception:
print("Cannot save to path %r" % save_path)
import traceback
traceback.print_exc()
# Save .blend file
if ok:
bpy.ops.wm.save_as_mainfile(filepath=save_path)

Comment on lines +98 to +103
@Override
public synchronized ModelKey getAssetKey() {
GltfModelKey gltf = new GltfModelKey(super.getAssetKey().getName());
gltf.setExtrasLoader(GltfExtrasLoader.INSTANCE);
return gltf;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Potential NullPointerException if super.getAssetKey() returns null. It is safer to perform a null check before accessing its properties.

    @Override
    public synchronized ModelKey getAssetKey() {
        ModelKey superKey = super.getAssetKey();
        if (superKey == null) {
            return null;
        }
        GltfModelKey gltf = new GltfModelKey(superKey.getName());
        gltf.setExtrasLoader(GltfExtrasLoader.INSTANCE);
        return gltf;
    }

Comment on lines +82 to +88
JsonObject jo = null;
try {
jo = extras.getAsJsonObject();
}
catch(Exception e) {
log.warn("Skipping extras:" + extras, e);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If extras is null, calling extras.getAsJsonObject() will throw a NullPointerException. A null check should be added before attempting to access it.

        JsonObject jo = null;
        if (extras != null) {
            try {
                jo = extras.getAsJsonObject();
            }
            catch(Exception e) {
                log.warn("Skipping extras:" + extras, e);
            }
        }

Comment on lines +132 to +150
protected Object toAttribute( JsonElement el, boolean nested ) {
try {
return toAttribute(el.getAsJsonObject(), nested);
} catch (Exception e) {
}

try {
return toAttribute(el.getAsJsonArray(), nested);
} catch (Exception e) {
}

try {
return toAttribute(el.getAsJsonPrimitive(), nested);
} catch (Exception e) {
}

log.warn("Unhandled extras element:" + el);
return null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using exceptions for control flow (catching Exception to try different types) is an anti-pattern that can be highly inefficient. Instead, use the built-in type check methods like isJsonObject(), isJsonArray(), and isJsonPrimitive() to safely determine the element type.

    protected Object toAttribute( JsonElement el, boolean nested ) {
        if (el == null || el.isJsonNull()) {
            return null;
        }
        if (el.isJsonObject()) {
            return toAttribute(el.getAsJsonObject(), nested);
        }
        if (el.isJsonArray()) {
            return toAttribute(el.getAsJsonArray(), nested);
        }
        if (el.isJsonPrimitive()) {
            return toAttribute(el.getAsJsonPrimitive(), nested);
        }

        log.warn("Unhandled extras element:" + el);
        return null;       
    }

Comment on lines +38 to +53
public void run() {
try {
String line;
while ((line = in.readLine()) != null) {
if (line.trim().length() > 0) {
if (progress != null) {
progress.progress(line);
} else {
logger.log(Level.INFO, "{0}", line);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The reader in is never closed, which can lead to resource leaks. Additionally, using e.printStackTrace() is discouraged; exceptions should be logged using the logger. We should close the reader in a finally block and log the exception properly.

    @Override
    public void run() {
        try {
            String line;
            while ((line = in.readLine()) != null) {
                if (line.trim().length() > 0) {
                    if (progress != null) {
                        progress.progress(line);
                    } else {
                        logger.log(Level.INFO, "{0}", line);
                    }
                }
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error reading output", e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e) {
                logger.log(Level.SEVERE, "Error closing reader", e);
            }
        }
    }

@neph1
neph1 marked this pull request as ready for review July 19, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant