Swift - Backendless error in hosted custom service

I am trying to use a hosted custom service in Backendless

I created a custom jar libraryand uploaded it in Backendless hosted custom service but it’s returning me an error when I try to invoke it using the SDK in Swift.

My Library is below:

SalvarContatosLibrary.java

    package com.mbaas.service;
    
    import com.backendless.Backendless;
    import com.backendless.servercode.IBackendlessService;
    
    import java.util.ArrayList;
    
    public class SalvarContatoLibrary implements IBackendlessService {
    
        public boolean salvarContatos(ArrayList<Contato> contato) {
    
            boolean retorno = true;
    
            if(contatos == null || contatos() == 0) {
                retorno = false;
            } else {
                for(Contato contato: contatos) {
                    Backendless.Persistence.save(contato);
                }
            }
    
            return retorno;
        }
    }

Contato.java

    package com.mbaas.service;
    
    import java.util.Date;
    
    /**
     * Created by guilhermedupas on 12/07/17.
     */
    
    public class Contato {
    
        private Usuario usuario;
        private int prioridade;
    
        private String objectId;
        private Date created;
        private Date updated;
        private String ownerId;
    }

Usuario.java

    package com.mbaas.service;
    
    import java.util.Date;
    
    /**
     * Created by guilhermedupas on 12/07/17.
     */
    
    public class Usuario {
    
        private String nome;
        private String foto;
        private Date dataNascimento;
        private String numeroTelefone;
        private String telefoneE164;
    
        private String objectId;
        private Date created;
        private Date updated;
        private String ownerId;
    }

And I am trying to invoke the method as the code below:

Swift Code

    func salvarContato() {
        
        let nomeServico = "SalvarContatoLibrary"
        let versaoServico = "1.0.0"
        let metodoServico = "salvarContatos"
        
        let contatosNSArray = contatos as! NSArray
        
        backendless?.customService.invoke(nomeServico, serviceVersion: versaoServico, method: metodoServico, args: contatosNSArray as! [Any],
            response: { (result: Any?) -> Void in
                print(result)
                
        }, error: { (fault: Fault?) -> Void in
            print("Erro contatos")
            print("Server reported an error to save the User: \(fault)")
        })
    }

The error it’s returning is:

Server reported an error to save the User: Optional(FAULT = '0' [ExceptionClass:"CodeRunnerException" {Msg:"Wrong number of arguments", Cause:"none"}] <ExceptionClass:&quot;CodeRunnerException&quot; {Msg:&quot;Wrong number of arguments&quot;, Cause:&quot;none&quot;}> )

is “contatosNSArray” and empty array?

No, “contatosNSArray” is not empty.

I tried now casting contatos to NSMutableArray

“contatosNSMutableArray = contatos as! NSMutableArray”

and it stoped retuning me the error but It’s returning a response as a number “0” and it is not saving the data.

What does contatorNSArray contain? The objects in there must structurally match the classes which are expected on the server.

It matches. I have made the jar library to contain the same classes that the app needs.

I will double check it tomorrow morning to certify that everything is Ok.

Please post the Swift classes here. Also, do your Java classes have any public get/set methods for the fields?

No. It doesn’t have any get/set methods. Is it mandatory?

The Swift classes are below:

class Usuario: NSObject, NSCoding {
    
    //MARK: Propriedades
    var nome: String?
    var foto: String?
    var dataNascimento: Date?
    var numeroTelefone: String?
    var telefoneE164: String?
    
    var objectId: String?
    var created: Date?
    var updated: Date?
    var ownerId: String?
    
    override init() {}
    
    required init(coder aDecoder: NSCoder) {
        
        nome = aDecoder.decodeObject(forKey: "nome") as? String
        foto = aDecoder.decodeObject(forKey: "foto") as? String
        dataNascimento = aDecoder.decodeObject(forKey: "dataNascimento") as? Date
        numeroTelefone = aDecoder.decodeObject(forKey: "numeroTelefone") as? String
        telefoneE164 = aDecoder.decodeObject(forKey: "telefoneE164") as? String
        
        objectId = aDecoder.decodeObject(forKey: "objectId") as? String
        created = aDecoder.decodeObject(forKey: "created") as? Date
        updated = aDecoder.decodeObject(forKey: "updated") as? Date
        ownerId = aDecoder.decodeObject(forKey: "ownerId") as? String
    }
    
    func encode(with aCoder: NSCoder) {
        
        if let nomeUsuario = nome {
            aCoder.encode(nomeUsuario, forKey: "nome")
        }
        
        if let fotoUsuario = foto {
            aCoder.encode(fotoUsuario, forKey: "foto")
        }
        
        if let dataNascimentoUsuario = dataNascimento {
            aCoder.encode(dataNascimentoUsuario, forKey: "dataNascimento")
        }
        
        if let numeroTelefoneUsuario = numeroTelefone {
            aCoder.encode(numeroTelefoneUsuario, forKey: "numeroTelefone")
        }
        
        if let telefoneE164Usuario = telefoneE164 {
            aCoder.encode(telefoneE164Usuario, forKey: "telefoneE164")
        }
        
        if let objectIdUsuario = objectId {
            aCoder.encode(objectIdUsuario, forKey: "objectId")
        }
        
        if let createdUsuario = created {
            aCoder.encode(createdUsuario, forKey: "created")
        }
        
        if let updatedUsuario = updated {
            aCoder.encode(updatedUsuario, forKey: "updated")
        }
        
        if let ownerIdUsuario = ownerId {
            aCoder.encode(ownerIdUsuario, forKey: "ownerId")
        }
    }
}
class Contato: NSObject, NSCoding {
    
    var contatoBackendless: Usuario?
    var prioridade: Int?
    
    override init() {}
    
    required init(coder aDecoder: NSCoder) {
        
        contatoBackendless = aDecoder.decodeObject(forKey: "contatoBackendless") as? Usuario
        confirmado = aDecoder.decodeObject(forKey: "prioridade") as? Int
    }
    
    func encode(with aCoder: NSCoder) {
        
        if let contatoIDoParty = contatoBackendless {
            aCoder.encode(contatoIDoParty, forKey: "contatoBackendless")
        }
        
        if let prioridadeContato = prioridade {
            aCoder.encode(prioridadeContato, forKey: "prioridade")
        }
    }
}

If all the fields are private, no data can be passed using these objects.

If you’d use version 4 of Backendless it automatically generates Swift code for the deployed services:
http://support.backendless.com/public/attachments/d44e41da44408f66447cb3d40f29538a.jpg&lt;/img&gt;

I am using version 3 of Backendless and it has the custom SDK to download but when I open the project it shows me some errors.

Swift code generation for version 3 does not work correctly.

Unless you plan to be on a paid plan on version 3, I recommend switching to version 4.

The free plans on version 3 will be discontinued on November 1st, 2017.

Regards,
Mark

Yes, I intend to do it. I just need to solve this question about the hosted custom service to migrate.

I would recommend the following approach:

  1. Modify your java code so it either declares public fields or get/set methods for the private fields.
  2. Create the jar for the service and deploy in the 4.0 app. This is so you can generate the Swift code for it.
  3. Once the swift code is generated, use it with your 3.x app.