ORACLE JVM RECOVERY

When Oracle JVM breaks, it rarely announces itself clearly. You get cascading invalid package errors, PL/SQL wrappers that suddenly fail to compile, or Java stored procedures returning cryptic ORA-29549 and ORA-29553 errors. This guide covers the full recovery sequence — from verifying prerequisites through reinstalling the JVM itself to restoring all dependent objects and validating the result.

Written against Oracle Database 11.2.0.3. Notes for 19c / 21c are included where the procedure differs. All steps run as DBA in SQL*Plus unless stated otherwise.

Before you start: Take a cold backup or export if at all possible. The JVM reinstallation procedure restarts the database in restricted mode and replaces core system objects. It is not reversible without a restore.


Recovery Sequence Overview

Work through the phases in order. Each phase is a prerequisite for the next — do not skip ahead if you find failures.

PhaseWhat it coversRequired if
1Restore CATPROCCATPROC status is not VALID in DBA_REGISTRY
2Reinstall JVMJAVAVM or CATJAVA is missing or INVALID
3Restore DBMS_CRYPTO grantsAfter any JVM reinstall, or when Java crypto calls fail
4Restore external directoryAfter JVM reinstall, or when directory objects are missing
5Restore Java schema userJava user account is locked, missing, or has lost privileges
6Reinstall custom Java objectsApplication Java classes are invalid or missing
7Functional testAlways — run after every recovery

Phase 1 — Restore CATPROC

CATPROC (Oracle Database Packages and Types) is a hard dependency of JVM. If it is invalid, the JVM reinstallation scripts will fail partway through. Fix it first.

Check its current status:

SELECT comp_id, comp_name, status
FROM dba_registry
WHERE comp_id = 'CATPROC';

If status is not VALID, proceed with the two-step fix below.

Step 1 — Recompile invalid objects

This is the quick path. utlrp.sql recompiles all invalid objects across the database in parallel. It resolves many CATPROC invalidity issues caused by incomplete patches or interrupted upgrades.

@$ORACLE_HOME/rdbms/admin/utlrp.sql

Re-check DBA_REGISTRY after completion. If CATPROC is now VALID, proceed to Phase 2. If still invalid, continue to Step 2.

Step 2 — Reinstall catalog and packages

This rebuilds the data dictionary catalog and all core PL/SQL packages from scratch. It takes significant time on large databases and will report many objects being replaced — that is expected.

@$ORACLE_HOME/rdbms/admin/catalog.sql
@$ORACLE_HOME/rdbms/admin/catproc.sql
@$ORACLE_HOME/rdbms/admin/utlrp.sql

Oracle 19c / 21c note: The scripts and procedure are identical. In a CDB environment, connect to CDB$ROOT as SYSDBA before running these — they operate at the container level and will apply across PDBs appropriately.


Phase 2 — Reinstall Oracle JVM

This is the core of the recovery. The procedure mounts the database, disables several background processes that would interfere with JVM replacement, recreates the Java system layer, and then runs the full JVM initialisation scripts. The database must be restarted as part of this process.

This procedure restarts the database. Coordinate a maintenance window. All active sessions will be terminated.

Step 1 — Mount the database

Shut down the database first, then bring it to mount state — not open. The JVM replacement must happen before normal operations resume.

SHUTDOWN IMMEDIATE;
STARTUP MOUNT;

Step 2 — Prepare init parameters

Before opening the database, disable three settings that would otherwise interfere with JVM reinstallation: the JIT compiler (which would attempt to compile Java classes as they load), system triggers (which fire on DDL and would conflict with the Java system recreation), and job queue processes (which would spawn background jobs during the install).

ALTER SYSTEM SET java_jit_enabled = FALSE;
ALTER SYSTEM SET "_system_trig_enabled" = FALSE;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 0;

Step 3 — Open in restricted mode

Open the database but restrict access to DBA sessions only. This prevents any application connections from hitting the database while the JVM is being rebuilt.

ALTER DATABASE OPEN;
ALTER SYSTEM ENABLE RESTRICTED SESSION;

Step 4 — Recreate the Java system layer

This statement drops and recreates the entire Java system within Oracle. It is the equivalent of wiping and reinstalling the JVM engine itself. It will take several minutes and produces no output during execution — that is normal.

CREATE OR REPLACE JAVA SYSTEM;
/

After it completes, verify the Java object table to confirm the system layer is present:

SELECT obj#, name
FROM obj$
WHERE type# IN (28, 29, 30)
   OR namespace = 32;

You should see thousands of rows. An empty result or very few rows means the CREATE OR REPLACE JAVA SYSTEM did not complete successfully — check the alert log before continuing.

Step 5 — Run JVM initialisation scripts

These scripts install all JVM components in the correct dependency order. Run them sequentially and do not interrupt. Each script may take several minutes.

-- Core JVM
@$ORACLE_HOME/javavm/install/initjvm.sql

-- Oracle XML with Java support
@$ORACLE_HOME/xdk/admin/initxml.sql
@$ORACLE_HOME/xdk/admin/xmlja.sql

-- Java catalog packages
@$ORACLE_HOME/rdbms/admin/catjava.sql

-- Expression Filter (Oracle 11g only — see note below)
@$ORACLE_HOME/rdbms/admin/catexf.sql

Oracle 12c / 19c / 21c note: catexf.sql (Expression Filter) was deprecated in 12c and the component does not exist in 19c/21c. Skip this script on any version from 12c onward — running it will produce errors.

Step 6 — Recompile all invalid objects

@$ORACLE_HOME/rdbms/admin/utlrp.sql

Step 7 — Reset init parameters and restart

Restore the three parameters that were disabled before the install, then perform a clean shutdown and normal startup.

ALTER SYSTEM SET java_jit_enabled = TRUE;
ALTER SYSTEM SET "_system_trig_enabled" = TRUE;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 10;

SHUTDOWN IMMEDIATE;

Start the database normally (outside SQL*Plus if using OS-managed startup, or via SQL*Plus):

STARTUP;

Step 8 — Verify JVM is restored

SELECT comp_id, comp_name, status
FROM dba_registry
WHERE comp_id IN ('JAVAVM', 'CATJAVA');

SELECT count(*), object_type, status
FROM all_objects
WHERE object_type LIKE '%JAVA%'
GROUP BY object_type, status
ORDER BY object_type;

Both JAVAVM and CATJAVA must be VALID, and the object counts should match the reference values from the oracle jvm diagnostics guide (SYS: ~20,500 JAVA CLASS on 11.2.0.3).

Oracle 19c / 21c — Multitenant note: In a CDB environment, JVM reinstallation for a PDB requires connecting directly to the target PDB as SYSDBA and running initjvm.sql and catjava.sql within that PDB context. The CREATE OR REPLACE JAVA SYSTEM command must also be run within the PDB. Modifying _system_trig_enabled is a CDB-level operation — set it from CDB$ROOT before opening the PDB.


Phase 3 — Restore DBMS_CRYPTO Grants

JVM reinstallation does not always preserve all privilege grants on system packages. DBMS_CRYPTO is a common casualty — any application code using Java cryptography or calling DBMS_CRYPTO directly from non-SYS schemas will fail if the public execute grant is missing.

Check whether the grant exists:

SELECT owner, table_name, grantee, privilege
FROM dba_tab_privs
WHERE owner = 'SYS'
  AND table_name = 'DBMS_CRYPTO'
  AND grantee = 'PUBLIC'
  AND privilege = 'EXECUTE';

If no rows are returned, restore the grant:

GRANT EXECUTE ON SYS.DBMS_CRYPTO TO PUBLIC;

Security note: Granting DBMS_CRYPTO execute to PUBLIC is appropriate in environments where all database users are trusted application accounts. In multi-tenant or shared environments, consider granting only to specific roles or users rather than PUBLIC.


Phase 4 — Restore External Directory

Oracle directory objects are database-level pointers to filesystem paths. They are used for external tables, log file output, and Java I/O operations. After a JVM reinstall or database rebuild, these objects may need to be recreated.

Step 1 — Verify the filesystem path exists

ls -la /opt/oracle/admin/<db_name>/external_tables/
# Create it if missing:
mkdir -p /opt/oracle/admin/<db_name>/external_tables/
chown oracle:oinstall /opt/oracle/admin/<db_name>/external_tables/

Step 2 — Recreate the Oracle directory object

-- Check if it already exists
SELECT directory_name, directory_path
FROM all_directories
WHERE owner = 'SYS';

-- Create or replace if missing/incorrect
CREATE OR REPLACE DIRECTORY LOG_DIR
  AS '/opt/oracle/admin/<db_name>/external_tables';

-- Grant access to the appropriate user or role
GRANT READ, WRITE ON DIRECTORY LOG_DIR TO PUBLIC;

Note: Replace <db_name> with your actual database name. Adjust the path and directory name to match your environment. Review which schemas actually need access before granting to PUBLIC.


Phase 5 — Restore the Java Schema User

If your application loads Java into a dedicated schema user (the standard pattern for keeping application Java separate from SYS), that user’s account and privileges need to be verified after any JVM recovery. A locked account or missing role grant will cause all Java calls from that schema to fail immediately.

Step 1 — Create or unlock the user

-- Check if user exists and is open
SELECT username, account_status
FROM dba_users
WHERE username = 'JAVA_OBJS';

-- Create if missing
CREATE USER java_objs IDENTIFIED BY <password>
  DEFAULT TABLESPACE <tablespace_name>;

ALTER USER java_objs QUOTA UNLIMITED ON <tablespace_name>;

-- Unlock if locked
ALTER USER java_objs ACCOUNT UNLOCK;
ALTER USER java_objs IDENTIFIED BY <password>;

Step 2 — Restore role grants

-- Check existing role grants
SELECT granted_role
FROM dba_role_privs
WHERE grantee = 'JAVA_OBJS';

-- Restore required roles
GRANT JAVASYSPRIV TO java_objs;
GRANT CONNECT TO java_objs;

Oracle 18c / 19c / 21c note: The JAVA_DEPLOY role was deprecated in Oracle Database 18c. Do not grant it on 18c and later — it no longer exists. On 11g and earlier, it was required to deploy Java stored procedures via loadjava.

Step 3 — Restore system privileges

-- Check existing system privileges
SELECT privilege
FROM dba_sys_privs
WHERE grantee = 'JAVA_OBJS';

-- Restore required privileges
GRANT CREATE PROCEDURE TO java_objs;
GRANT CREATE TABLE TO java_objs;

Phase 6 — Reinstall Custom Java Objects

After the JVM itself is restored and the schema user is in place, any application Java classes that were loaded into the database need to be redeployed. The general pattern is: drop the old objects, load from the JAR, compile sources, resolve classes, recreate PL/SQL wrapper functions, and re-grant execute privileges.

Step 1 — Drop existing Java objects from the schema

Run from the OS as the Oracle OS user. dropjava removes all Java classes, sources, and resources that were loaded from a given JAR.

dropjava -v -u java_objs/<password> /path/to/your-application.jar

Step 2 — Load the JAR

loadjava -u java_objs/<password> -resolve /path/to/your-application.jar -grant public

The -resolve flag forces Oracle to verify all class dependencies during load rather than deferring them. Load errors are much easier to diagnose at this stage than at runtime. The -grant public flag makes the loaded classes accessible to all schemas — scope this down if your application does not require public access.

Step 3 — Compile sources and resolve classes

If your JAR includes Java source files (not just compiled classes), compile them explicitly. Then resolve all classes to confirm dependencies are satisfied.

-- Compile Java sources (if applicable)
ALTER JAVA SOURCE "java_objs"."com/example/YourClass" COMPILE;

-- Resolve Java classes
ALTER JAVA CLASS "java_objs"."com/example/YourClass" RESOLVE;

Verify that everything loaded cleanly:

SELECT object_name, object_type, status
FROM all_objects
WHERE owner = 'JAVA_OBJS'
  AND object_type LIKE '%JAVA%'
ORDER BY object_type, object_name;

All rows must show VALID. Any INVALID rows indicate unresolved dependencies or compilation errors — check USER_ERRORS for detail.

Step 4 — Recreate PL/SQL wrapper functions

Java stored procedures are called through thin PL/SQL wrapper functions that map SQL types to Java types. These need to be recreated if the schema was rebuilt.

-- Example wrapper pattern
CREATE OR REPLACE FUNCTION java_objs.your_function(input VARCHAR2)
  RETURN VARCHAR2
AS LANGUAGE JAVA
  NAME 'com.example.YourClass.yourMethod(java.lang.String) return java.lang.String';
/

-- Grant access to the wrappers
GRANT EXECUTE ON java_objs.your_function TO PUBLIC;

-- Create public synonym for schema-transparent access
CREATE PUBLIC SYNONYM your_function FOR java_objs.your_function;

Oracle 19c / 21c note: The loadjava and dropjava utilities still exist but are deprecated in 19c and later in favour of DBMS_JAVA.loadjava and DBMS_JAVA.dropjava PL/SQL APIs. Both approaches work in 19c/21c. For new deployments on 19c+, prefer the PL/SQL API as the OS utilities may be removed in a future release.


Phase 7 — Functional Test

Do not close the maintenance window until you have confirmed that Java execution works end-to-end, not just that objects are VALID in the data dictionary.

Test 1 — Confirm JVM components are valid

SELECT comp_id, comp_name, status
FROM dba_registry
WHERE comp_id IN ('JAVAVM', 'CATJAVA', 'CATPROC');

All three must be VALID.

Test 2 — Confirm Java object counts

SELECT owner, object_type, status, COUNT(*)
FROM all_objects
WHERE object_type LIKE '%JAVA%'
GROUP BY owner, object_type, status
ORDER BY owner, object_type;

SYS should show approximately 20,500 JAVA CLASS objects (11.2.0.3). All rows should be VALID — any INVALID rows in SYS require another pass of utlrp.sql or a repeated JVM install.

Test 3 — Execute Java from SQL

Call one of your application’s Java wrapper functions directly from SQL. This confirms the full execution path: SQL engine → PL/SQL wrapper → Java class resolution → JVM execution → return value.

SELECT your_function('test_input') FROM dual;

A clean return value confirms success. An ORA-00904 (invalid identifier) means the synonym or wrapper function is missing. An ORA-29549 or ORA-29553 means the class is still invalid or the Java Pool is insufficient — refer to the diagnostics guide to investigate memory.

Test 4 — Confirm DBMS_JAVA is accessible

SELECT owner, object_name, object_type, status
FROM dba_objects
WHERE object_name = 'DBMS_JAVA'
ORDER BY owner, object_type;

Both SYS.DBMS_JAVA PACKAGE and SYS.DBMS_JAVA PACKAGE BODY must be VALID. A valid spec with an invalid body is a common post-install failure mode.


Common Failure Patterns and Fixes

SymptomMost likely causeAction
ORA-29549 — class has changedJava class reloaded but old session state cachedDisconnect and reconnect all sessions; bounce the application connection pool
ORA-29553 — class not foundClass invalid or Java Pool exhaustedRun Phase 6 again; check v$sgastat Java Pool free memory
ORA-00904 — invalid identifier on wrapper callPublic synonym missing or pointing to wrong schemaDrop and recreate synonym; verify GRANT EXECUTE is in place
utlrp.sql completes but JAVA CLASS objects remain INVALIDUnsatisfied class dependency — a referenced class is missing or also invalidRun Phase 6 again with -resolve; check USER_ERRORS on the invalid objects
initjvm.sql fails with ORA-01017 or privilege errorsNot running as SYSDBA, or restricted session not enabledConfirm connection string uses / as sysdba; confirm RESTRICTED SESSION is active
JVM valid after recovery but broken again after next DB restartInit parameters persisted incorrectly, or SPFILE not updatedVerify java_jit_enabledJOB_QUEUE_PROCESSES, and _system_trig_enabled are reset with SCOPE=BOTH

Summary

The full recovery sequence — CATPROC, JVM reinstall, package grants, directory objects, schema user, custom Java objects, functional test — is thorough but deterministic. Each phase has a clear success criterion before moving to the next. If you are scripting this for automation, the key checks to gate on are: DBA_REGISTRY status after each phase, and a live Java function call at the end that exercises the complete execution path.

Keep a copy of your loadjava commands, wrapper function DDL, and privilege grant statements in version control. A JVM recovery at 2 AM is significantly less painful when the reinstallation of custom objects is a single script rather than archaeology through change logs.