Java Question Automating AbsObjectWrapper

tchart

Well-Known Member
Licensed User
Longtime User
Ok, so I have a library which I need to wrap a bunch of classes. Not knowing java and reading the example I think I need to use AbsObjectWrapper.

The "creating libraries" tutorial shows this example;

B4X:
@ShortName("Rect")
    public static class RectWrapper extends AbsObjectWrapper<Rect> {
        public void Initialize(int Left, int Top, int Right, int Bottom) {
            Rect r = new Rect(Left, Top, Right, Bottom);
            setObject(r);
        }
        public int getLeft() {return getObject().left;} public void setLeft(int Left) {getObject().left = Left;}
        public int getTop() {return getObject().top;} public void setTop(int Top) {getObject().top = Top;}
        public int getRight() {return getObject().right;} public void setRight(int Right) {getObject().right = Right;}
        public int getBottom() {return getObject().bottom;} public void setBottom(int Bottom) {getObject().bottom = Bottom;}
        /**
         * Returns the horizontal center.
         */
        public int getCenterX() {return getObject().centerX();};
        /**
         * Returns the vertical center.
         */
        public int getCenterY() {return getObject().centerY();};

    }

I understand this but what if I have 100+ classes with various objects etc

Is there any way to automatically generate the above "mapping" ie these types of lines;

public int getCenterY() {return getObject().centerY();};

Thanks
Trevor
 

agraham

Expert
Licensed User
Longtime User
You don't actually need to use AbsObjectWrapper. This is from an edited composite of Erels' responses from email interchanges I had with him during the development of Basic4android and also later when I was deciding whether to extend AbsObjectWrapper for a library or not (I didn't in the end).

And for the libraries developer it is useful when the library is really just
a thin wrapper over an existing class.

As a general rule for libraries developers, methods should accept the actual
object and not the wrapper. For example:
[TextReader] public void Initialize(InputStream InputStream) {

And idealy return the wrapper object:
[File] public static InputStreamWrapper OpenInput(String Dir, String FileName)

This makes the framework much more extensible and open for new
implementations (with the same actual class or a subclass). As an example
you can initialize TextReader with a future NetworkStreamWrapper.
Returning the wrapper object allows the user to treat the returned object
directly without first assigning it to a local variable.

If you return a wrapper then the user can write the following code:

Dim n As BigDecimal ' This creates a BigDecimalWrapper
n.Add(12).Add(23)

If you return the actual object then the user will need to write:
Dim n, n2 As BigDecimal
n2 = n.Add(12)
n2 = n2.Add(23)
However for this "chaining" to work your wrapper doesn't actually need to extend AbsObjectWrapper, it just needs to return itself or an instance of its own type so I have to admit that I am still, after all this time, not really sure what the benefits of extending AbsObjectWrapper are. I'm probably being a bit thick and missing the obvious but I haven't found it necessary to do so yet!
 

tchart

Well-Known Member
Licensed User
Longtime User
Hello agraham

Firstly thanks for the reply.

So if I understand you I can just wrap the class without using AbsObjectWrapper. Your example was slightly hard to follow as one section mentions InputStreamWrapper and then your example shows BigDecimalWrapper.

So for instance, lets start with something simple like this;

SpatialReference (ArcGIS_Android 0.1 API)

How would I wrap something like that?

Thanks and sorry to monopolise your time.

Trevor
 

tchart

Well-Known Member
Licensed User
Longtime User
Alright, I think I have figured it out.

One thing I have noticed is that there are many pieces of information missing from the tutorials. For example when I managed to create my wrapper of another library you have to create a "dummy" xml file to include the other library into your B4A project. I only figured this out by looking at the Admob library/tutorial. While I found my error message in the forums the fix of "include the library" in B4A did not help as it doesnt explain anywhere how to achieve this.

One thing I have yet to figure out is how to expose multiple "new types" via a single library. For example, Im using a geomtery library, so there are objects for point, lines and polygons.

What I mean is when looking at the BigNumber library it wraps the BigDecimal object which is declared in B4A. What would I need to do to have the library expose another object as well? Is this even possible or would I need seperate wrappers for Point, Line and Polygon?

In Eclipse I created two classes but when tryng to generate the XML document it would only let me select one class.

Thanks agraham for your help so far.

PS I will post an A-Z tutorial for dummies once Ive figured the whole thing out.
 

agraham

Expert
Licensed User
Longtime User
One thing I have yet to figure out is how to expose multiple "new types" via a single library.
Declare the additional classes "static".
I will post an A-Z tutorial for dummies once Ive figured the whole thing out.
If you haven't already found it there's one here.
 

tchart

Well-Known Member
Licensed User
Longtime User
Ah yes, thanks agraham that tutorial is better. There appear to be two and that one is more comprehensive.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
In most cases you should not extend AbsObjectWrapper.

AbsObjectWrapper, which is treated specially in the IDE, was created in order to simplify the "wrapping" of the views.
By using AbsObjectWrapper you can make use of Java's polymorphism features.

Lets take for example the method Activity.AddView.
B4X:
public void AddView(android.view.View View, int Left, int Top , int Width, int Height) {
The first parameter is the native view.
It is not possible to pass ButtonWrapper as the first parameter as it doesn't extends View. In Basic4ppc this issue was solved by adding a ControlRef property which exposed the internal native control. However it was a bit ugly.
Basic4android solves this issue by implementing ObjectWrapper interface (which AbsObjectWrapper implements). The IDE knows that ButtonWrapper wraps android.view.Button. Therefore when the native object is required, the IDE adds getObject code automatically.

One rule that you should remember is that a class implementing ObjectWrapper should not have any instance variables.
Take for example the following B4A code:

B4X:
Dim b1, b2 As Button
b1.Initialize("")
b2 = b1

----------------
This code is translated to:
ButtonWrapper b1 = new ButtonWrapper();
ButtonWrapper b2 = new ButtonWrapper();
b1.Initialize(...) //creates the native view
b2 = b1

Now consider this code:
B4X:
Dim b1, b2 as Button
Dim o As Object
b1.Initialize()
o = b1
b2 = o
------------------
Translated to:
ButtonWrapper b1 = new ButtonWrapper();
ButtonWrapper b2 = new ButtonWrapper();
Object o = new Object();
b1.Initialize(...)
o = b1.getObject(); //returns the native object
b2.setObject(o);
If b1 had any instance variables then they get lost when passed to 'o'.

To conclude this complicated topic, in most cases you should not extend AbsObjectWrapper.
 
Top