3

In the below code, the api gets a "Person" obj in POST body,

My technical requirement:

  • If only one field of Person is sent, only that field must be compared to object from db.
  • if there is a change, then call save() if not just return object from db.
  • How to change the code below to be more generic and CLEAN. Any utility methods that is object type independent?
    public Model.Person save(Model.Person in) {
        String updateId = in.getId();
        System.out.println("updateId = " + updateId);
        Model.Person pExisting = get(updateId);
        Model.Person.Builder outBuild = Model.Person.newBuilder(pExisting);
        boolean hasChange = false;
        //Change only fields that are provided in POST body.
        //TODO do not compare createTs, updateTs -- they are not provided in POST to update.
        if(!in.getFirstName().isEmpty()){ //TODO - Find if there is a generic util in protobuf java.
            if(!Objects.equals(in.getFirstName(), pExisting.getFirstName())){
                outBuild.setFirstName(in.getFirstName());
                hasChange = true;
            }
        }
        if(!in.getLastName().isEmpty()){
            if(!Objects.equals(in.getLastName(), pExisting.getLastName())){
                outBuild.setLastName(in.getLastName());
                hasChange = true;
            }
        }
        
        if(!hasChange){
            System.out.println("Nothing to update ... "+System.currentTimeMillis() );
            return pExisting;
        }
        final Model.Person updatePerson = outBuild.build();
        map.put(updateId,updatePerson); //TODO move to H2 or postgres later
        return updatePerson;
    }

Sample model

syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";
package my.model;

option java_outer_classname = "Model"; //muni.api.Model
option java_generic_services = false; //default, prevents complex generic
option java_multiple_files = false; //default behavior

message Person{
  //Output only
  string id=3;
  string firstName = 4;
  string lastName= 5;
  ContactChannels contactChannels = 8;
  //Output only
  google.protobuf.Timestamp createTime = 1;
  //Output only
  google.protobuf.Timestamp updateTime = 2;
}

enter image description here

Espresso
  • 5,378
  • 4
  • 35
  • 66
  • Is it proto2, proto3, or proto3 with the new experimental "optional" support? It kinda matters (because you simply can't do it (reliably) for the middle one) – Marc Gravell Oct 09 '20 at 17:57
  • @MarcGravell, I'm using proto3. Edited title & included a snippet from .proto. Since this is a new proj, I can migrate to anything - how do I use proto3+optional ? This is for java. Do I need an updated protoc-gen-java? Currently using: protoc-gen-openapiv2-v2.0.0-beta.5-windows-x86_64.exe – Espresso Oct 09 '20 at 18:27
  • 1
    Look for `--experimental_allow_proto3_optional` in https://chromium.googlesource.com/external/github.com/protocolbuffers/protobuf/+/refs/heads/master/CHANGES.txt - it is this flag (relatively new) that enables presence tracking in proto3. Without that: if a value is zero, it isn't sent; it it is non-zero:it is sent. Then you just need to check each field in turn via he presence API – Marc Gravell Oct 09 '20 at 18:50
  • @MarcGravell, Your comment is useful i.e for testing "no/sent" - Thanks. My question is bit broader -- i.e a utility class that would generically (1) diff the fields sent based on p3-optional (2) determine if there is any field to update i.e field value different (3) crate a new object with merged/updated fields. Then the client code calls repo.save(updatedObj). Perhaps there is a way to do it generically. – Espresso Oct 09 '20 at 19:09
  • Hi @MarcGravell, Looks like that p3_optional feature is affecting deserialization to json. Is there any workaround? https://stackoverflow.com/questions/64362567/protobuf-3-how-to-resolve-missing-method-getidcase-classes-generated-with. – Espresso Oct 15 '20 at 12:56

0 Answers0