Support Topics Documentation Slack YouTube Blog

Swift - Backendless error in hosted custom service


(Guilherme Cortada Dupas) #1

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;}> )


(Mark Piller) #2

is “contatosNSArray” and empty array?


(Guilherme Cortada Dupas) #3

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.


(Mark Piller) #4

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


(Guilherme Cortada Dupas) #5

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.


(Mark Piller) #6

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


(Guilherme Cortada Dupas) #7

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")
        }
    }
}

(Mark Piller) #8

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</img>


(Guilherme Cortada Dupas) #9

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.


(Mark Piller) #10

Swift code generation for version 3 does not work correctly.


(Mark Piller) #11

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


(Guilherme Cortada Dupas) #12

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


(Mark Piller) #13

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.