The code explained below can be found in test/test_plugin and test/test_app/application_context_test.
My First Plugin Object
ShapeInterface.h
We want to design to interface. So here's the interface. To let the Qt system know the interface, it is declared using Q_DECLARE_INTERFACE.
#ifndef SHAPE_INTERFACE_H_
#define SHAPE_INTERFACE_H_
class ShapeInterface
{
public:
  
  
  virtual ~ShapeInterface() {}
  virtual void draw () = 0;
};
Q_DECLARE_INTERFACE(ShapeInterface, "org.qic.test.ShapeInterface/1.0")
#endif
RectanglePlugin.h
Now, a plugin to implement the interface. This class has to derive from QObject and all the interfaces it implements. Use Q_INTERFACES to tell Qt the interfaces it implements. To define properties that refer to other objects, the QObject * should be wrapped in QVariant.
#ifndef RECTANGLE_PLUGIN_H_
#define RECTANGLE_PLUGIN_H_
#include <QObject>
#include <QtDebug>
#include <QVariant>
#include "ShapeInterface.h"
class RectanglePlugin : public QObject, public ShapeInterface
{
  
  Q_OBJECT
  
  Q_INTERFACES( ShapeInterface)
  
  
  Q_PROPERTY(QString name READ name WRITE setName)
  Q_PROPERTY(int size READ size WRITE setSize)
  
  Q_PROPERTY(QVariant canvasObj READ canvasObj WRITE setCanvasObj)
public:
  RectanglePlugin ()
  {
    _name = "rectangle_plugin";
    _size = 0;
  }
  void draw ();
  QVariant canvasObj ()
  {
    
    return QVariant::fromValue(_canvasObj);
  }
  void setCanvasObj (QVariant obj)
  {
    _canvasObj = obj.value<QObject *>();
  }
  int size () const
  {
    return _size;
  }
  void setSize (int size)
  {
    _size = size;
  }
  QString name () const
  {
    return _name;
  }
  void setName (QString & name)
  {
    _name = name;
  }
public slots:
  
  void init ()
  {
    _size = 200;
  }
  void setCanvasSize (int size)
  {
    _size = size;
  }
  
  void destroy ()
  {
    qDebug() << "In RectanglePlugin destroy method.";
  }
protected:
  QObject * _canvasObj;
  QString _name;
  int _size;
};
#endif
RectanglePlugin.cpp
Export the plugin using Q_EXPORT_PLUGIN2
#include <QtDebug>
#include <QString>
#include <QtPlugin>
#include <QtXml/QDomElement>
#include "RectanglePlugin.h"
void RectanglePlugin::draw ()
{
  qDebug()<< "Drawing RectanglePlugin. ";
}
Q_EXPORT_PLUGIN2(rectangle_plugin, RectanglePlugin)
rectangle_plugin.pro
HEADERS += RectanglePlugin.h \
           ../ShapeInterface.h 
SOURCES += RectanglePlugin.cpp 
INCLUDEPATH += ../ \
               ./ \
               ../../../include 
CONFIG += debug \
          warn_on \
          qt \
          plugin 
TEMPLATE = lib 
Another Plugin Object
Canvas Object emits sizeChanged signal when its size property is set.
CanvasPlugin.h
#ifndef CANVAS_PLUGIN_H_
#define CANVAS_PLUGIN_H_
#include <QObject>
#include <QList>
#include <QMetaType>
#include <QVariant>
#include <QtDebug>
#include "ShapeInterface.h"
class CanvasPlugin : public QObject, public ShapeInterface
{
  Q_OBJECT
  Q_INTERFACES(ShapeInterface)
  Q_PROPERTY(int size READ size WRITE setSize)
  
  Q_PROPERTY(QVariant rectangleObj READ rectangleObj WRITE setRectangleObj)
public:
  CanvasPlugin ()
  {
    _rectangleObj = NULL;
    _size = 0;
  }
  virtual ~CanvasPlugin () {}
  virtual void draw ();
  QVariant rectangleObj ()
  {
    return QVariant::fromValue(_rectangleObj);
  }
  void setRectangleObj (QVariant obj)
  {
    _rectangleObj = obj.value<QObject *>();
  }
  int size () const
  {
    return _size;
  }
  void setSize (int size)
  {
    if (size != _size)
    {
      _size = size;
      emit sizeChanged(_size);
    }
  }
public slots:
  
  void init ()
  {
    _size = 200;
  }
signals:
  void sizeChanged(int newValue);
protected:
  QObject * _rectangleObj;
  int _size;
};
#endif
CanvasPlugin.cpp
#include <QtDebug>
#include <QString>
#include <QtPlugin>
#include "CanvasPlugin.h"
void
CanvasPlugin::draw ()
{
  qDebug() << "Drawing CanvasPlugin.";
  if (_rectangleObj)
  {
    ShapeInterface * shape = qobject_cast<ShapeInterface *>(_rectangleObj);
    shape->draw();
  }
}
Q_EXPORT_PLUGIN2(canvas_plugin, CanvasPlugin)
canvas_plugin.pro
HEADERS += ../ShapeInterface.h \
           CanvasPlugin.h 
SOURCES += CanvasPlugin.cpp 
INCLUDEPATH += ../../../include \
               ./ \
               ../ 
CONFIG += debug \
          warn_on \
          qt \
          plugin 
TEMPLATE = lib 
Configuration File
Now the configuration file to wire up the objects.
<objects>
<object id="rectangle" 
        plugin="${QIC_DIR}/test/test_plugin/rectangle_plugin/librectangle_plugin.so"
        init-method="init" destroy-method="destroy" >
        <property name="name">
                <value><null/></value>
        </property>
        <property name="size">
                <value>100</value>
        </property>
</object>
<object id="canvas" 
        plugin="${QIC_DIR}/test/test_plugin/canvas_plugin/libcanvas_plugin.so" >
        <property name="rectangleObj" ref="rectangle">
        </property>
</object>
<!-- Wire the signal and slot. -->
<wire type="auto">
        <sender id="canvas" signal="sizeChanged(int)">
        </sender>
        <receiver id="rectangle" method="setCanvasSize(int)">
        </receiver>
</wire>
</objects>
Test the application
QString base = qic::Util::getEnvVariable("QIC_DIR");
base.append("/test/test_app/application_context_test/");
qic::XmlApplicationContext ctx( 
                QStringList() << (base + "application_context_10.xml") );
QObject * obj = ctx.getObject("canvas");
ShapeInterface * shape = qobject_cast<ShapeInterface *>(obj);
shape->draw();
obj->setProperty("size", 111);
obj = ctx.getObject( "rectangle");
int size = obj->property("size").value<int>();