summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam S Fulton <wsf@fultondesigns.co.uk>2016-03-11 19:47:31 +0000
committerWilliam S Fulton <wsf@fultondesigns.co.uk>2016-03-11 19:47:31 +0000
commitcd6c8806f08f9482b80102f3fa87bbc7f93178a0 (patch)
tree761945abf34b40dccb11744f39de747d23c9d78f
parentdc4e0ab0f6595f53e103b60b0e2a75d598a2c809 (diff)
downloadswig-interfaces.tar.gz
Documentation and CHANGES entry for interface featureinterfaces
-rw-r--r--CHANGES.current10
-rw-r--r--Doc/Manual/CSharp.html4
-rw-r--r--Doc/Manual/Contents.html1
-rw-r--r--Doc/Manual/Java.html330
4 files changed, 344 insertions, 1 deletions
diff --git a/CHANGES.current b/CHANGES.current
index 77c628e9b..956f7e08b 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -5,6 +5,16 @@ See the RELEASENOTES file for a summary of changes in each release.
Version 3.0.9 (in progress)
===========================
+2016-03-11: wsfulton
+ [Java C#] Add support for treating C++ base classes as Java interfaces
+ instead of Java proxy classes. This enable some sort of support for
+ multiple inheritance. The implementation is in swiginterface.i and
+ provides additional macros (see Java.html for full documentation):
+
+ %interface(CTYPE)
+ %interface_impl(CTYPE)
+ %interface_custom("PROXY", "INTERFACE", CTYPE)
+
2016-03-01: wsfulton
Add rstrip encoder for use in %rename. This is like the strip encoder but
strips the symbol's suffix instead of the prefix. The example below
diff --git a/Doc/Manual/CSharp.html b/Doc/Manual/CSharp.html
index 0cbc9ec24..26f0c740e 100644
--- a/Doc/Manual/CSharp.html
+++ b/Doc/Manual/CSharp.html
@@ -233,6 +233,7 @@ javabody -&gt; csbody
javafinalize -&gt; csfinalize
javadestruct -&gt; csdestruct
javadestruct_derived -&gt; csdestruct_derived
+javainterfacecode -&gt; csinterfacecode
</pre></div>
</li>
@@ -300,6 +301,9 @@ $*javaclassname -&gt; $*csclassname
$javaclazzname -&gt; $csclazzname
$javainput -&gt; $csinput
$jnicall -&gt; $imcall
+$javainterfacename -&gt; $csinterfacename
+$&amp;javainterfacename -&gt; $&amp;csinterfacename
+$*javainterfacename -&gt; $*csinterfacename
</pre></div>
</li>
diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html
index 55d16ee1a..856223ea3 100644
--- a/Doc/Manual/Contents.html
+++ b/Doc/Manual/Contents.html
@@ -997,6 +997,7 @@
<li><a href="Java.html#Java_proper_enums_classes">Proper Java enum classes</a>
<li><a href="Java.html#Java_typeunsafe_enums_classes">Type unsafe enum classes</a>
</ul>
+<li><a href="Java.html#Java_interfaces">Interfaces</a>
</ul>
<li><a href="Java.html#Java_directors">Cross language polymorphism using directors</a>
<ul>
diff --git a/Doc/Manual/Java.html b/Doc/Manual/Java.html
index dae6edc01..08309d9f7 100644
--- a/Doc/Manual/Java.html
+++ b/Doc/Manual/Java.html
@@ -83,6 +83,7 @@
<li><a href="#Java_proper_enums_classes">Proper Java enum classes</a>
<li><a href="#Java_typeunsafe_enums_classes">Type unsafe enum classes</a>
</ul>
+<li><a href="#Java_interfaces">Interfaces</a>
</ul>
<li><a href="#Java_directors">Cross language polymorphism using directors</a>
<ul>
@@ -3331,6 +3332,251 @@ public final class Beverage {
</pre>
</div>
+<H3><a name="Java_interfaces">25.4.6 Interfaces</a></H3>
+
+
+<p>
+By default SWIG wraps all C++ classes as Java classes.
+As Java only supports derivation from a single base class, SWIG has to ignore all
+bases except the first when a C++ class inherits from more than one base class.
+However, there is a family of SWIG macros that change the default wrapping and allows a C++ class
+to be wrapped as a Java interface instead of a Java class.
+These macros provide a way to support some sort of multiple inheritance as there is no limit to
+the number of interfaces that a Java class can inherit from.
+</p>
+
+<p>
+When a C++ class is wrapped as a Java interface, a Java proxy class is still needed.
+The <tt>swiginterface.i</tt> library file provides three macros for marking a C++ class to be
+wrapped as a Java interface.
+There is more than one macro in order to provide a choice for choosing the Java interface and Java proxy names.
+</p>
+
+<table BORDER summary="Java interface macros">
+<tr VALIGN=TOP>
+ <td><b>Interface Macro Name</b></td>
+ <td><b>Description</b></td>
+</tr>
+<tr>
+ <td><tt>%interface(CTYPE)</tt></td>
+ <td>Proxy class name is unchanged, interface name has <tt>SwigInterface</tt> added as a suffix for C++ class <tt>CTYPE</tt>.</td>
+</tr>
+<tr>
+ <td><tt>%interface_impl(CTYPE)</tt></td>
+ <td>Proxy class name has <tt>SwigImpl</tt> as a suffix, interface name has <tt>SwigInterface</tt> added as a suffix for C++ class <tt>CTYPE</tt>.</td>
+</tr>
+<tr>
+ <td><tt>%interface_custom("PROXY", "INTERFACE", CTYPE)</tt></td>
+ <td>Proxy class name is given by the string <tt>PROXY</tt>, interface name is given by the string <tt>INTERFACE</tt> for C++ class <tt>CTYPE</tt>. The <tt>PROXY</tt> and <tt>INTERFACE</tt> names can use the <a href="SWIG.html#SWIG_advanced_renaming">string formatting functions</a> used in <tt>%rename</tt>.</td>
+</tr>
+</table>
+
+<p>
+The table below has a few examples showing the resulting proxy and interface names.
+</p>
+
+<table BORDER summary="Java interface macro examples">
+<tr VALIGN=TOP>
+ <td><b>Example Usage</b></td>
+ <td><b>Proxy Class Name</b></td>
+ <td><b>Interface Class Name</b></td>
+</tr>
+<tr>
+ <td><tt>%interface(Base)</tt></td>
+ <td><tt>Base</tt></td>
+ <td><tt>BaseSwigInterface</tt></td>
+</tr>
+<tr>
+ <td><tt>%interface_impl(Base)</tt></td>
+ <td><tt>BaseSwigImpl</tt></td>
+ <td><tt>Base</tt></td>
+</tr>
+<tr>
+ <td><tt>%interface_custom("BaseProxy", "IBase", Base)</tt></td>
+ <td><tt>BaseProxy</tt></td>
+ <td><tt>IBase</tt></td>
+</tr>
+<tr>
+ <td><tt>%interface_custom("%sProxy", "IBase", Base)</tt></td>
+ <td><tt>BaseProxy</tt></td>
+ <td><tt>IBase</tt></td>
+</tr>
+<tr>
+ <td><tt>%interface_custom("%sProxy", "%sInterface", Base)</tt></td>
+ <td><tt>BaseProxy</tt></td>
+ <td><tt>BaseProxyInterface</tt></td>
+</tr>
+<tr>
+ <td><tt>%interface_custom("%sProxy", "%(rstrip:[Proxy])sInterface", Base)</tt></td>
+ <td><tt>BaseProxy</tt></td>
+ <td><tt>BaseInterface</tt></td>
+</tr>
+</table>
+
+<p>
+The 2nd last example shows the names used in the string formatting functions.
+The input for <tt>PROXY</tt> that <tt>"%s"</tt> expands to is the proxy name, that is, Base.
+The input for <tt>INTERFACE</tt> that <tt>"%s"</tt> expands to is the proxy name, that is, <tt>BaseProxy</tt>.
+</p>
+<p>
+The last example shows <tt>rstrip</tt> and in this case strips the <tt>Proxy</tt> suffix and then adds on <tt>Interface</tt>.
+</p>
+
+<p>
+Consider the following C++ code:
+</p>
+
+<div class="code">
+<pre>
+namespace Space {
+ struct Base1 {
+ virtual void Method1();
+ };
+ struct Base2 {
+ virtual void Method2();
+ };
+ struct Derived : Base1, Base2 {
+ };
+ void UseBases(const Base1 &amp;b1, const Base2 &amp;b2);
+}
+</pre>
+</div>
+
+<p>
+By default all classes are wrapped and are available in Java, but, <tt>Derived</tt>
+has all bases ignored except the first.
+SWIG generates a warning for the above code:
+</p>
+
+<div class="shell">
+<pre>
+example.i:10: Warning 813: Warning for Derived, base Base2 ignored.
+Multiple inheritance is not supported in Java.
+</pre>
+</div>
+
+<p>
+If we decide to wrap the two base classes as interfaces and add the following before SWIG parses the above example code:
+</p>
+
+<div class="code">
+<pre>
+%include &lt;swiginterface.i&gt;
+%interface_impl(Space::Base1);
+%interface_impl(Space::Base2);
+</pre>
+</div>
+
+<p>
+then two interface files are generated, Base1.java and Base2.java in addition to proxy class files, Base1SwigImpl.java and Base2SwigImpl.java.
+The contents of interface file Base1.java for <tt>Base1</tt> is shown below:
+</p>
+
+<div class="code">
+<pre>
+public interface Base1 {
+ long Base1_GetInterfaceCPtr();
+ void Method1();
+}
+</pre>
+</div>
+
+<p>
+The proxy class in Base1SwigImpl.java for Base1 is as it would have been if <tt>%interface</tt> was not used,
+except the name has changed to <tt>Base1SwigImpl</tt> and it implements the appropriate base:
+</p>
+
+<div class="code">
+<pre>
+public class Base1SwigImpl implements Base1 {
+...
+ public long Base1_GetInterfaceCPtr() {
+ return exampleJNI.Base1SwigImpl_Base1_GetInterfaceCPtr(swigCPtr);
+ }
+
+ public void Method1() {
+ exampleJNI.Base1SwigImpl_Method1(swigCPtr, this);
+ }
+...
+}
+</pre>
+</div>
+
+<p>
+In fact any class deriving from <tt>Base</tt> will now implement the interface instead of
+deriving from it (or ignoring the base in the case of multiple base classes).
+Hence the <tt>Derived</tt> proxy class will now implement both bases:
+</p>
+
+<div class="code">
+<pre>
+public class Derived implements Base1, Base2 {
+...
+ public long Base1_GetInterfaceCPtr() {
+ return exampleJNI.Derived_Base1_GetInterfaceCPtr(swigCPtr);
+ }
+
+ public long Base2_GetInterfaceCPtr() {
+ return exampleJNI.Derived_Base2_GetInterfaceCPtr(swigCPtr);
+ }
+
+ public void Method1() {
+ exampleJNI.Derived_Method1(swigCPtr, this);
+ }
+
+ public void Method2() {
+ exampleJNI.Derived_Method2(swigCPtr, this);
+ }
+...
+}
+</pre>
+</div>
+
+<p>
+Wherever a class marked as an interface is used, such as the <tt>UseBases</tt> method in the example,
+the interface name is used as the type in the Java layer:
+</p>
+
+<div class="code">
+<pre>
+ public static void UseBases(Base1 b1, Base2 b2) {
+ exampleJNI.UseBases(b1.Base1_GetInterfaceCPtr(), b1, b2.Base2_GetInterfaceCPtr(), b2);
+ }
+</pre>
+</div>
+
+<p>
+Note that each Java interface has a method added to obtain the correct C++ pointer for passing to the native function -
+<tt>Base1_GetInterfaceCPtr</tt> for <tt>Base1</tt>.
+This method is similar to the <tt>getCPtr</tt> method in the proxy classes.
+In fact, as shown above in the <tt>Derived</tt> class, the proxy classes implement
+this generated interface by calling a native method (<tt>Derived_Base1_GetInterfaceCPtr</tt>)
+which calls an appropriate C++ cast of the pointer up the inheritance chain.
+</p>
+
+<p>
+The interface macros are implemented using the <tt>interface</tt> feature and typemaps.
+For example:
+</p>
+
+<div class="code">
+<pre>
+%define %interface(CTYPE...)
+%feature("interface", name="%sSwigInterface") CTYPE;
+INTERFACE_TYPEMAPS(CTYPE)
+%enddef
+</pre>
+</div>
+
+<p>
+The feature accepts one attribute called <tt>name</tt>, which is the name of the Java interface mentioned earlier.
+The <tt>INTERFACE_TYPEMAPS</tt> macro implements the typemaps and can be viewed in the
+<tt>swiginterface.i</tt> file and contain
+the usual Java typemaps for generating code plus the <tt>javainterfacecode</tt>
+typemap which is only used when a class is marked with the <tt>interface</tt> feature.
+See <a href="Java.html#Java_code_typemaps">Java code typemaps</a> for details.
+</p>
+
<H2><a name="Java_directors">25.5 Cross language polymorphism using directors</a></H2>
@@ -5585,6 +5831,8 @@ For example, <tt>$javaclassname</tt> is replaced by the proxy classname <tt>Foo<
expands to the proxy classname when wrapping <tt>Foo *&amp;</tt>.
If the type does not have an associated proxy class, it expands to the type wrapper class name, for example,
<tt>SWIGTYPE_p_unsigned_short</tt> is generated when wrapping <tt>unsigned short *</tt>.
+The class name is fully qualified with the package name when using the
+<a href="SWIGPlus.html#SWIGPlus_nspace">nspace feature</a>.
</p>
<p>
@@ -5715,6 +5963,35 @@ This special variable expands to the intermediary class name. Usually this is th
unless the jniclassname attribute is specified in the <a href="Java.html#Java_module_directive">%module directive</a>.
</p>
+<p>
+<b><tt>$javainterfacename</tt></b><br>
+This special variable is only expanded when the <tt>interface</tt> feature is applied to a class.
+It works much like <tt>$javaclassname</tt>, but instead of expanding to the proxy classname,
+it expands to the value in the <tt>name</tt> attribute in the <tt>interface</tt> feature.
+For example:
+</p>
+
+<div class="code"><pre>
+%feature("interface", name="MyInterface") MyClass;
+%typemap(jstype) MyClass "$&amp;javainterfacename"
+%typemap(jstype) MyClass * "$javainterfacename"
+</pre></div>
+
+<p>
+will result in the <tt>jstype</tt> typemap expanding to <tt>MyInterface</tt> for both
+<tt>MyClass</tt> and <tt>MyClass *</tt>.
+The interface name is fully qualified with the package name when using the
+<a href="SWIGPlus.html#SWIGPlus_nspace">nspace feature</a>.
+</p>
+
+<p>
+<b><tt>$interfacename</tt></b><br>
+This special variable is only expanded when the <tt>interface</tt> feature is applied to a class.
+It expands to just the interface name and is thus different to <tt>$javainterfacename</tt>
+in that it is not fully qualified with the package name when using the
+<a href="SWIGPlus.html#SWIGPlus_nspace">nspace feature</a>.
+</p>
+
<H3><a name="Java_typemaps_for_c_and_cpp">25.9.8 Typemaps for both C and C++ compilation</a></H3>
@@ -5848,9 +6125,39 @@ Below shows an example modifying the finalizer, assuming the <tt>delete</tt> met
</div>
+<p><tt>%typemap(javainterfacecode, declaration="...", cptrmethod="...")</tt></p>
+<div class="indent">
+<p>
+The code in this typemap is added to the body of a Java proxy class but only when a class is
+marked with the <tt>interface</tt> feature.
+The typemap is used in the proxy class marked with the interface feature as well as all proxy classes derived from the marked C++ class,
+as they are all generated as implementing the Java interface.
+The default typemap used in the <tt>%interface</tt> family of macros mentioned in
+the <a href="Java.html#Java_interfaces">Java interfaces</a> section,
+where <tt>CTYPE</tt> is the C++ class macro argument,
+is as follows:
+</p>
+
+<div class="code"><pre>
+%typemap(javainterfacecode,
+ declaration=" long $interfacename_GetInterfaceCPtr();\n",
+ cptrmethod="$interfacename_GetInterfaceCPtr") CTYPE %{
+ public long $interfacename_GetInterfaceCPtr() {
+ return $imclassname.$javaclazzname$interfacename_GetInterfaceCPtr(swigCPtr);
+ }
+%}
+</pre></div>
+</div>
+
+<p>
+The special variable <tt>$interfacename</tt> is expanded into the
+name specified in the <tt>interface</tt> feature.
+</p>
+
<p>
<b>Compatibility Note:</b> In SWIG-1.3.21 and earlier releases, typemaps called "javagetcptr" and "javaptrconstructormodifiers" were available.
These are deprecated and the "javabody" typemap can be used instead.
+The <tt>javainterfacecode</tt> typemap and interface feature was introduced in SWIG-3.0.9.
</p>
<p>
@@ -5866,6 +6173,7 @@ In summary the contents of the typemaps make up a proxy class like this:
[ javafinalize typemap ]
public synchronized void <i>delete</i>() [ javadestruct OR javadestruct_derived typemap ]
[ javacode typemap ]
+[ javainterfacecode typemap]
... proxy functions ...
}
</pre>
@@ -5876,6 +6184,11 @@ Note the <tt><i>delete</i>()</tt> methodname and method modifiers are configurab
</p>
<p>
+The <tt>javainterfacecode</tt> typemap is only used when bases are marked by the <tt>interface</tt>
+feature and the <tt>implements</tt> list will also then be expanded to include these Java interfaces.
+</p>
+
+<p>
The type wrapper class is similar in construction:
</p>
@@ -5907,8 +6220,23 @@ The type wrapper class is similar in construction:
The "javaimports" typemap is ignored if the enum class is wrapped by an inner Java class, that is when wrapping an enum declared within a C++ class.
</p>
+<p>The Java interface turned on by the <tt>interface</tt> feature is fairly simple:</p>
+<div class="code">
+<pre>
+[ javaimports typemap ]
+public interface [ javainterfacename ] {
+[ javainterfacecode:cptrmethod typemap attribute ]
+... interface declarations ...
+}
+</pre>
+</div>
+
+<p>
+where <tt>javainterfacename</tt> is the <tt>name</tt> attribute in the <a href="Java.html#Java_interfaces">interface feature</a>.
+</p>
+
<p>
-The defaults can be overridden to tailor these classes.
+The defaults can be overridden to tailor the generated classes.
Here is an example which will change the <tt>getCPtr</tt> method and constructor from the default public access to protected access.
If the classes in one package are not using the classes in another package, then these methods need not be public and removing access to these low level implementation details, is a good thing.
If you are invoking SWIG more than once and generating the wrapped classes into different packages in each invocation, then you cannot do this as you will then have different packages.