Android Question Convert new type object into map

Lucas Siqueira

Active Member
Licensed User
Longtime User
How can I find out all the attributes of an object that I created with type? I have several types created in an app, and I needed to convert them to map. I know that I can create functions, but every time I change an attribute of the type, I would have to go to my functions and modify them to adapt to the map.

How could I do this conversion?


B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Type cliente (id As Int , nome As String)
End Sub

Public Sub Initialize
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
End Sub

Private Sub Button1_Click
    
    Dim cliente1 As cliente
    cliente1.Initialize
    cliente1.id = 1
    cliente1.nome = "lucas"
    
    Log(cliente1)
        
    Dim mcliente As Map = 'code ?????
    
    Log(mcliente)
End Sub
 
Solution
Thanks for the idea, it gave me the idea of the solution

code function
B4X:
Sub ConvertObjectToMap(obj As Object) As Map
    Dim sObject As String = obj 'ignore
    
    Dim mObject As Map
    mObject.Initialize
    
    Dim matcher1 As Matcher = Regex.Matcher("(\w+)=([\w\d]+)", sObject)
    
    Do While matcher1.Find
        Dim key As String = matcher1.Group(1)
        Dim value As Object = matcher1.Group(2)
        mObject.put(key, value)
    Loop
    
    Return mObject
End Sub


code complete
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Type cliente (id As Int , nome As String)
End Sub

Public Sub Initialize
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1...

emexes

Expert
Licensed User
Longtime User
I got as far as:
B4X:
Dim cliente1 As cliente
cliente1.Initialize
cliente1.id = 1
cliente1.nome = "lucas"

Dim s As String = cliente1
s = s.Replace(CRLF, "")    'every third field is followed by a CRLF ie ASCII 10
Log(s)

Dim m As Matcher = Regex.Matcher("(?:\[|, |)([a-zA-Z][a-zA-Z0-9]*)\=", s)
Do While m.Find
    Log(m.Group(1))
Loop
Log output:
Waiting for debugger to connect...
Program started.
[IsInitialized=true, id=1, nome=lucas]
IsInitialized
id
nome
 
Last edited:
Upvote 1

Lucas Siqueira

Active Member
Licensed User
Longtime User
Thanks for the idea, it gave me the idea of the solution

code function
B4X:
Sub ConvertObjectToMap(obj As Object) As Map
    Dim sObject As String = obj 'ignore
    
    Dim mObject As Map
    mObject.Initialize
    
    Dim matcher1 As Matcher = Regex.Matcher("(\w+)=([\w\d]+)", sObject)
    
    Do While matcher1.Find
        Dim key As String = matcher1.Group(1)
        Dim value As Object = matcher1.Group(2)
        mObject.put(key, value)
    Loop
    
    Return mObject
End Sub


code complete
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Type cliente (id As Int , nome As String)
End Sub

Public Sub Initialize
End Sub

Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
End Sub

Private Sub Button1_Click
    
    Dim cliente1 As cliente
    cliente1.Initialize
    cliente1.id = 1
    cliente1.nome = "lucas"
    
    Log(cliente1)
    
    Dim mcliente As Map = ConvertObjectToMap(cliente1)
    
    Log(mcliente)
    
End Sub

Sub ConvertObjectToMap(obj As Object) As Map
    Dim sObject As String = obj 'ignore
    
    Dim mObject As Map
    mObject.Initialize
    
    Dim matcher1 As Matcher = Regex.Matcher("(\w+)=([\w\d]+)", sObject)
    
    Do While matcher1.Find
        Dim key As String = matcher1.Group(1)
        Dim value As Object = matcher1.Group(2)
        mObject.put(key, value)
    Loop
    
    Return mObject
End Sub
 
Upvote 1
Solution

MicroDrie

Well-Known Member
Licensed User
Longtime User
Another possibility is that you used the 'cliente' Type to directly put the contents of the key and value into the map.
Direct Type to map:
Private Sub Button1_Click
    
    Dim cliente1 As cliente
    cliente1.Initialize
    cliente1.id = 1
    cliente1.nome = "lucas"
    
    Log(cliente1)
        
    Dim mcliente As Map = ConvertObjectToMap(cliente1)
    
'    --- direct Type to map
    Dim tObj As cliente
    tObj = Createcliente(2, "Siqueira")
    Log($"cliente type:  ${tObj}"$)
    mcliente.Put(tObj.id, tObj.nome)
    Log($"mcliente: ${mcliente}"$)
End Sub

Public Sub Createcliente (id As Int, nome As String) As cliente
    Dim t1 As cliente
    t1.Initialize
    t1.id = id
    t1.nome = nome
    Return t1
End Sub
In case you are using Regex to sanitize the input for the map key and value, you should do this in the call to the 'Createcliente' routine.
 
Upvote 0

emexes

Expert
Licensed User
Longtime User
Dim mcliente As Map = ConvertObjectToMap(cliente1)

Is there already an existing ConvertObjectToMap function hidden in a library or class somewhere (other than the one written by @Lucas Siqueira in this thread) ?

B4XSerializator does half the job, and it looks like it wouldn't be too hard to write the other half, but if somebody else has already done that then I'm happy not to.
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Longtime User
Is there already an existing ConvertObjectToMap function hidden in a library or class somewhere (other than the one written by @Lucas Siqueira in this thread) ?
What object structure are we talking about here? The example defines the object as the 'cliente' Type with only two variables. If it is a Type with more than two variables, you can put the 'cliente' Type in a list (useful for string values only) or object (can contain different types of variables). By applying the 'cliente' Type you only need to adjust the write and readback action, you don't need a library for that.

It is still not clear to me what goal is to be achieved. With that, I cannot judge which possible means (like B4XSerializator library) as means could be used effectively.
 
Upvote 0

emexes

Expert
Licensed User
Longtime User
It is still not clear to me what goal is to be achieved.

The goal is to have a general way to convert custom type variables - including custom types that you don't know what's in them, eg you just received them over a network connection - into Maps, eg:

B4X:
Dim cliente1 As cliente : cliente1.Initialize
cliente1.id = 1
cliente1.nome = "lucas"

'ideally could then do something like this:
'Dim m As Map = cliente1.As(Map)
'but instead we have to do it by hand, individually for each custom type, like this:

Dim m As Map : m.initialize
m.Put("IsInitialized", cliente1.IsInitialized)
m.Put("id", cliente1.id)
m.Put("nome", cliente1.nome)

Log(cliente1.As(String).Replace(CRLF, ""))
Log(m)
Log output:
Waiting for debugger to connect...
Program started.
[IsInitialized=true, id=1, nome=lucas]
(MyMap) {IsInitialized=true, id=1, nome=lucas}
 
Last edited:
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Longtime User
The goal is to have a general way to convert custom type variables - including custom types that you don't know what's in them, eg you just received them over a network connection - into Maps, eg:
So with Regex you filter the "id" and the "nome" from the external data, I understand that. But what is the added value of letting the "id" and the "nome" go through the Type "cliente"? That is, you get out the same thing that you put in there first?
 
Upvote 0

emexes

Expert
Licensed User
Longtime User
As I understood the question, it was: how do you get the field names and data out of a custom type or variable, when you don't know what the field names are?

The OP's example contains the custom type definition, so the field names are self-evident and the question seems moot, but... what about if you're trying to write a function to go digging around in an unknown custom type variable looking for data relevant to your program? Or trying to extract data from a custom type variable from a different program, for which you don't have the source code or custom type definition.

For example, here is an unknown custom type variable serialized and received from another program. If we dump out the ASCII text from it, we can see it contains data, but we can't reliably get at that data because we don't have the custom type (or class) definition.

I have gotten as far as being able to extract field names and data from a serialized unknown custom type variable that is "flat" single layer, but still mulling over how to best handle a custom type that contains nested custom types. There is an easy way which would get the job done (short term) but it is not the right way (long term) and given that the OP here apparently has access to the custom type definitions, I think I'll leave further investigation on hold until somebody actually truly needs it.

B4X:
Dim bc As ByteConverter
Dim seri As B4XSerializator
Dim compr As CompressedStreams
   
Dim h As String = "789CED544D6FD34010F5366D532271E24054408A10572AB904A91CF3D1484649" & _
                  "8BEA1489131A6747F1D2CDAEB5DE849AFFCEC7CE38441CE2F2077AB1EC99E7F7" & _
                  "76DE1B6D57BC8EA228EB7F3BC37B58151ACF56A0CC9BAF0E97AAF40EBCB2C657" & _
                  "051E0594781A1E499918E51568F503655B8876A87DC65C2D3476C5ABBD5C9BBA" & _
                  "4D34274D3487A136833B148418E3D43A0423487566256A714CE5D9E86D7CCED0" & _
                  "2F088E5FE20F1731C346565BC7B054E90DD6DDA195D5B6BB2E904B37B8B42C72" & _
                  "7D3B1FCC93D9A568D104C99588E86C04BEFE6ED075C5CBBDC314E8CAFF584232" & _
                  "57B00A7E9CEEA530A14704874D044F426DA25CE98985E9260EA5E8901B4A4A8D" & _
                  "5CA7593FDA128B9CE799C2164FB08956C697DE1AE48006523A2CCBA680A06ED3" & _
                  "99DA0FE59C7A87E863F12CBCBFEBBFEF8D6083BD94547A3716E43F98F3DA4D8E" & _
                  "639DAD5DC6BD214A6717776C72EAC1D769737220EB543ED9D22F42E28CB988FB" & _
                  "71CC7F86FC8C771567759B0ED8A139EA303B8DC85A541A2AE77319889BACA7DE" & _
                  "03D647BBE53AD8EEC22C649D7722161E43D5A9671A3BB5795C91C715695811BE" & _
                  "447C4E1BF262AF86A52689749A4488028695C7EDC6419A5BE74992E42131BEB5" & _
                  "BBAF606ACD92CAD1CE5198680BFE88BFC91C18DB75A6F178073A617E6B75B866" & _
                  "DB5B4CC84599E55F6D6DB3E7841707AD9FBF7EFF01F4A16E4A"

Dim ReceivedBytes() As Byte = bc.HexToBytes(h)

'these two lines fail because we don't know the structure of the received object
'Dim o As Object = seri.ConvertBytesToObject(ReceivedBytes)
'Log(o)

Dim UncompressedBytes() As Byte = compr.DecompressBytes(ReceivedBytes, "zlib")

Dim Temp As String = ""
Dim EndOfLine As String = ""

For I = 0 To UncompressedBytes.Length - 1
    Dim Ch As Int = Bit.And(UncompressedBytes(I), 0xFF)
    If Ch >= 32 And Ch <= 126 Then
        Temp = Temp & Chr(Ch)
        EndOfLine = CRLF
    Else
        Temp = Temp & EndOfLine
        EndOfLine = ""  
    End If
Next

Log(Temp)
Log output:
Waiting for debugger to connect...
Program started.
"
b4j.example.main$_registrationtype
IsInitialized
Vehicle
b4j.example.main$_vehicletype
IsInitialized
Make
DeLorean
Model
DMC-12
Year
1981
Color
Silver
Body
Coupe
Rego
OUTATIME
VIN
Owner
b4j.example.main$_persontype
IsInitialized
Name
b4j.example.main$_nametype
IsInitialized
FirstName
Fred
MiddleName
Joseph
LastName
Flintstone
Address
b4j.example.main$_addresstype
IsInitialized
Street1
345 Cave Stone Road
Street2
Suburb
Bedrock
State
Colorado
Postcode
81411
Country
USA
Telephone
Birthdate
b4j.example.main$_datetype
IsInitialized
Year
Month
Day
Driver
b4j.example.main$_persontype
IsInitialized
Name
b4j.example.main$_nametype
IsInitialized
FirstName
Fred
MiddleName
Joseph
LastName
Flintstone
Address
b4j.example.main$_addresstype
IsInitialized
Street1
345 Cave Stone Road
Street2
Suburb
Bedrock
State
Colorado
Postcode
81411
Country
USA
Telephone
Birthdate
b4j.example.main$_datetype
IsInitialized
Year
Month
Day
Other
b4j.example.main$_othertype
IsInitialized
aByte
aShort
aInt
aLong
aFloat
aDouble
aBoolean
aString
aBlob
 
Upvote 0

sirjo66

Well-Known Member
Licensed User
Longtime User
Dim matcher1 As Matcher = Regex.Matcher("(\w+)=([\w\d]+)", sObject)
IMHO you need to change this line into:
B4X:
 Dim matcher1 As Matcher = Regex.Matcher("(\w+)=(.+)", sObject)

First of all because "\w" match [a-zA-Z0-9_] so "\d" is not necessary.
But the problem is that "\w" don't match spaces, symbols, punctuation and so on.
For example, try your line with this string:
B4X:
nome=hola, que tal ?
and take a look at the result

EDIT: I make some test ad it is very hard to make a valid solution
For example,
B4X:
nome = "hola, mi nombre es = que tu"
No found solution
 
Last edited:
Upvote 0
Top