Why do I get a NoObjectFactoryException?

This page is only relevant for applications using Ice 3.6 and earlier. Factories are still supported in Ice 3.7, where they are known as value factories, but their use is less common now that classes with operations are deprecated.

Ice::NoObjectFactoryException exception indicates that the Ice run time failed to unmarshal an instance of a Slice class.

On this page:

Diagnosing NoObjectFactoryException

The first step in diagnosing the cause of this exception is to determine the Slice type that Ice tried to unmarshal. NoObjectFactoryException provides this information in a data member named type, so one solution is to modify your receiver to print the exception. A simpler alternative is to run the receiver with the Ice.Trace.Slicing property enabled to generate log information about object unmarshaling:

Ice.Trace.Slicing=1

Once you've discovered the problematic type ID, review its corresponding Slice definition to determine whether the class is abstract or concrete. An abstract Slice class is one that defines (or inherits) operations, whereas a concrete Slice class contains only data members. Knowing which kind of class Ice tried to unmarshal provides important clues as to the cause of the NoObjectFactoryException.

If the Slice class is abstract, Ice cannot unmarshal the object unless the application has registered an object factory for the type ID. This rule does not apply to the Objective-C or Ruby language mappings, but for all other languages your next step should be to verify that the receiver has registered its object factory correctly.

If the Slice class is concrete, Ice uses a language-specific mechanism to instantiate the class without requiring the application to supply a factory. In this situation, you need to determine why this mechanism is failing.

The sections below explore the potential reasons for NoObjectFactoryException in more detail.

Object Factories and NoObjectFactoryException

In all language mappings except Objective-C and Ruby, the application must supply object factories for abstract Slice classes that are transferred by value. An occurrence of NoObjectFactoryException may simply indicate that the application neglected to provide a factory, or that the application registered the factory incorrectly.

The communicator operation addObjectFactory registers a factory for a particular Slice type:

Slice
interface Communicator
{
    void addObjectFactory(ObjectFactory factory, string id);
    // ...
};

The operation expects an object that implements the ObjectFactory interface and the type ID of the Slice class. Type IDs use the same format as scoped symbols in C++, such as "::MyModule::MyClass". Note however that a literal type ID in your code increases the likelihood of a NoObjectFactoryException because a literal type ID might be misspelled, or its value might be obsoleted by a change to the name of a Slice class or one of its enclosing modules. To avoid this situation and gain some assistance from your compiler, use the ice_staticId method instead:

C++
communicator->addObjectFactory(myFactory, "::MyModule::MyClass"); // DON'T
communicator->addObjectFactory(myFactory, MyModule::MyClass::ice_staticId()); // DO

Now there's no risk of a misspelling, and the compiler will remind you to fix your code if a Slice symbol changes.

Similar bugs can lurk in the implementation of your object factory. Consider this example:

Java
class MyObjectFactory implements Ice.ObjectFactory
{
    public Ice.Object create(String type)
    {
        if(type.equals("::MyModule::MClass")) // Oops, typo!
        {
            return new MyClassI();
        }

        return null;
    }

    public void destroy()
    {
    }
}

Ice raises a NoObjectFactoryException if the create method returns null, as caused in the preceding example by a misspelling. Again, we strongly recommend that you use ice_staticId instead:

Java
if(type.equals(MyModule.MyClass.ice_staticId()))
{
    return new MyClassI();
}

In Objective-C or Ruby, the Ice run time is more flexible about its treatment of abstract Slice classes because both languages have the ability to add methods to an existing class. If Ice cannot find an object factory for a given type ID, it creates an instance of the generated class (despite the fact that this class is logically abstract), with the assumption that the application will add an implementation of the Slice-defined operations to the generated class if required by the application. As a result, you only need to register an object factory with Objective-C and Ruby if you want Ice to use a class other than the generated class.

Refer to the relevant language mappings in the Ice Manual for more details about registering object factories.

Package Metadata versus Classes

In Java, a NoObjectFactoryException is often caused by the use of package metadata in combination with incorrect configuration of the communicator. Consider the following example:

Slice
[["java:package:uni"]]
module Demo
{
    class Student
    {
        string id;
    };
}; 

The slice2java compiler would normally map the Demo::Student class to the Java class Demo.Student, but the presence of the metadata causes the compiler to generate uni.Demo.Student instead.

The problem arises when the Ice run time in the receiver attempts to unmarshal an instance of Student. The encoding for an object includes a string representing the type ID of its class, which in this case is ::Demo::Student. Since this Slice class is concrete, Ice does not require the application to supply a factory. However, in order to create an instance of Student, the Ice run time must be able to dynamically load the Java class that corresponds to the encoded type ID. Ice uses the standard mapping rules by default, which produces a class name (Demo.Student) that does not exist. Consequently, Ice fails to unmarshal the object and eventually raises NoObjectFactoryException to the application.

The solution is to configure the Java run time such that it can translate Slice type IDs into Java class names. Two configuration properties exist for this purpose:

  • Ice.Package.Module=package
    This property specifies the package prefix that the Ice run time should prepend to any mapped class name whose outermost Slice module is Module. In our example above, we can define a property like this:

    Ice.Package.Demo=uni
  • Ice.Default.Package=package
    This property specifies the name of a package to prepend to any mapped class name. Using our example again, we could define this property as follows:

    Ice.Default.Package=uni

Using one (or both) of these properties, you can supply the Ice run time with the information it needs to instantiate a concrete Slice class.

Class Inheritance and Slicing Too Much

It is important to understand the semantics of unmarshaling Ice objects when class inheritance is involved. Briefly, the Ice run time in the receiver makes every effort to create the most-derived type that was marshaled by the sender. If Ice cannot instantiate the most-derived type, it proceeds up the object's inheritance hierarchy and attempts to instantiate each superclass until it succeeds or until it reaches a superclass that is incompatible with the formal type. Consider these classes:

Slice
class Animal
{
    string genus;
};

class Dog extends Animal
{
    string furColor;
};

class Labrador extends Dog
{
    boolean registered;
};

interface Sender
{
    void sendDog(Dog d);
}; 

The Slice definition of the sendDog operation specifies a contract stating that the receiver expects an instance of the formal type Dog, but the actual type may also be a subclass of Dog.

Suppose a sender transfers an instance of Labrador but the Ice run time in the receiver cannot instantiate that type. In this situation, Ice attempts to create an instance of Dog instead. This is known as slicing and refers to the fact that Ice slices off the state associated with the unknown type and instead constructs an instance of a less-derived type. If Ice also fails to instantiate Dog, it raises NoObjectFactoryException because slicing the object any further (to Animal) would result in an object whose type violates the contract specified by the Slice definition.

The Ice.Trace.Slicing property logs unmarshaling of objects. Each time the run time cannot instantiate a Slice class, it logs a message that includes the offending type ID. If an object is an instance of a derived class, Ice logs a message for each type in the inheritance hierarchy. This information will assist you in determining the cause of a NoObjectFactoryException.

If you'd like more information about the Ice encoding for objects, please refer to the Ice protocol.

NoObjectFactoryException for Concrete Slice Classes

Ice also throws a NoObjectFactoryException when its language-specific mechanism has failed to instantiate a concrete Slice class. Here are some possible reasons for this situation:

  • In Java, the generated class may not be present in the receiver's class path.
  • In C++ and Objective-C, the object code for the generated class might not be linked into the application.
  • In C#, the application may lack a reference to the assembly that contains the generated class.
  • In a scripting language, the application might not have loaded the Slice file that defines the class.

Mismatched Slice Definitions and NoObjectFactoryException

Finally, a NoObjectFactoryException can easily occur when the sender and receiver use incompatible Slice definitions. This frequently happens when Slice types are changed without propagating that change to all communicating parties. Renaming a Slice class or one of its enclosing modules causes this situation.

See Also