0
@Override
public Long createPost(Request request) {

    Base.open();

    ObjectMapper mapper = new ObjectMapper();

    try {
        Post newPost  = mapper.readValue(request.body(), Post.class);
//        Map values = ... initialize map
//        newPost.saveIt();

    } catch (IOException ex) {
        Logger.getLogger(PostServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
    }

    Base.close();

    return 1L;
}

From the official docs, this Map values = ... initialize map is not clear. I can do newPost.set("first_name", "Sam") but is there a better way instead of setting values likes this?

kittu
  • 6,662
  • 21
  • 91
  • 185
  • I see you are not using ActiveWeb, what technology do you use to process web requests? What is the Request class? – ipolevoy Mar 24 '17 at 21:53
  • @ipolevoy java spark – kittu Mar 24 '17 at 21:54
  • @ipolevoy The request class from `spark`. Here is the link for request class: http://javadoc.io/doc/com.sparkjava/spark-core/2.5.4 – kittu Mar 24 '17 at 21:56
  • @ipolevoy also I have issue at http://stackoverflow.com/questions/43009622/java-lang-illegalargumentexception-number-of-arguments-must-be-even-at-org-java – kittu Mar 24 '17 at 21:57

2 Answers2

1

I'm not familiar with Spark (I'm the author of ActiveWeb ), but you can use filters to open/close connections instead of polluting your service classes:

http://sparkjava.com/documentation.html#filters

Additionally, if you can convert your request parameters into a java.util.Map, you then do this:

Post post = new Post();
post.fromMap(parameters); 
if(post.save()){
    //display success
}else{
    Errors errors = post.errors();
    //display errors
}

This is an example from ActiveWeb, but will help you with Spark too: https://github.com/javalite/activeweb-simple/blob/master/src/main/java/app/controllers/BooksController.java

ipolevoy
  • 5,432
  • 2
  • 31
  • 46
  • I have seen the example but didn't understand. How do I convert request body/params to map? I have the data inside `request.body()` so I do `post.fromMap(request.body())`?? – kittu Mar 24 '17 at 22:12
  • 1
    you need to look into Spark docs, as this is not related to ActiveJDBC. If you used ActiveWeb, it is a one liner: `post.fromMap(parameters1st());` – ipolevoy Mar 24 '17 at 22:18
1

If I'm understanding correctly, you are looking at how to take values from a POST request and then use ActiveJDBC to save those values. I'm quite new as well and we are in the beginning stages of our app, but we are using SparkJava with ActiveJDBC.

The example is actual code, I didn't have time to simplify it. But basically we created a POJO for the model class. We originally extended the org.javalite.activejdbc.Model but we needed to handle audit fields (create, update user/time) and help translate from JSON, so we extended this with a custom class called CecilModel. But CecilModel extends the Model class.

We have a controller that receives the request. The request comes in as JSON that matches the field names of our model class. In our custom CecilModel class we map the JSON to a Map which then we use Model.fromMap method to hyrdrate the fields and puts it into our custom model POJO. We don't need the getters or setters, it's more for convenience. We just need our JSON request to have the same names as in our model.

Below is our code but maybe you can peek through it to see how we are doing it.

Our table model pojo.

package com.brookdale.model;

import java.sql.Timestamp;

import org.javalite.activejdbc.Model;
import org.javalite.activejdbc.annotations.BelongsTo;
import org.javalite.activejdbc.annotations.BelongsToParents;
import org.javalite.activejdbc.annotations.IdGenerator;
import org.javalite.activejdbc.annotations.IdName;
import org.javalite.activejdbc.annotations.Table;

import com.brookdale.model.activejdbc.CecilModel;

// This class handles mapping of data from the database to objects
// and back, including custom selection queries.

@Table("RECURRINGITEMSCHEDULE")
@BelongsToParents({
    @BelongsTo(foreignKeyName="itemID",parent=Item.class),
    @BelongsTo(foreignKeyName="contactAgreementID",parent=ContactAgreement.class),
    @BelongsTo(foreignKeyName="unitOfMeasureCode",parent=UnitOfMeasure.class)
})
@IdGenerator("SQ_RECURRINGITEMSCHEDULE.nextVal")
@IdName("recurringItemScheduleID")
public class RecurringItem extends CecilModel {

    public Long getRecurringItemScheduleID() {
        return getLong("recurringItemScheduleID");
    }
    public void setRecurringItemScheduleID(Long recurringItemScheduleID) {
        set("recurringItemScheduleID",recurringItemScheduleID);
    }
    public Long getContactAgreementID() {
        return getLong("contactAgreementID");
    }
    public void setContactAgreementID(Long contactAgreementID) {
        set("contactAgreementID",contactAgreementID);
    }
    public Long getItemID() {
        return getLong("itemID");
    }
    public void setItemID(Long itemID) {
        set("itemID",itemID);
    }
    public Double getUnitChargeAmt() {
        return getDouble("unitChargeAmt");
    }
    public void setUnitChargeAmt(Double unitChargeAmt) {
        set("unitChargeAmt",unitChargeAmt);
    }
    public Integer getUnitQty() {
        return getInteger("unitQty");
    }
    public void setUnitQty(Integer unitQty) {
        set("unitQty",unitQty);
    }
    public String getUnitOfMeasureCode() {
        return getString("unitOfMeasureCode");
    }
    public void setUnitOfMeasureCode(String unitOfMeasureCode) {
        set("unitOfMeasureCode",unitOfMeasureCode);
    }
    public Timestamp getLastGeneratedPeriodEndDate() {
        return getTimestamp("lastGeneratedPeriodEndDate");
    }
    public void setLastGeneratedPeriodEndDate(Timestamp lastGeneratedPeriodEndDate) {
        set("lastGeneratedPeriodEndDate",lastGeneratedPeriodEndDate);
    }
    public Timestamp getEffEndDate() {
        return getTimestamp("effEndDate");
    }
    public void setEffEndDate(Timestamp effEndDate) {
        set("effEndDate",effEndDate);
    }
    public Timestamp getEffStartDate() {
        return getTimestamp("effStartDate");
    }
    public void setEffStartDate(Timestamp effStartDate) {
        set("effStartDate",effStartDate);
    }

    @Override
    public void validate() {
        validatePresenceOf("unitofmeasurecode","itemid","unitqty","effstartdate","unitChargeAmt","contactAgreementID");
        validateNumericalityOf("itemid","unitQty","contactAgreementID");
        // check to make sure this is an update operation
        if (!this.isNew()) {
            RecurringItem ridb = RecurringItem.findById(this.getId());
            if (ridb.getLastGeneratedPeriodEndDate() != null) {
                if (this.getItemID() != ridb.getItemID())
                    this.addError("itemid", "Item can not be updated once a charge has been created.");
                if (!this.getEffStartDate().equals(ridb.getEffStartDate()))
                    this.addError("effstartdate", "Effective start date can not be updated once a charge has been created.");
                if (this.getUnitChargeAmt() != ridb.getUnitChargeAmt())
                    this.addError("unitchargeamt", "Unit charge amount can not be updated after last generated period end date has been set.");
                if (this.getUnitQty() != ridb.getUnitQty())
                    this.addError("unitqty", "Unit quantity can not be updated after last generated period end date has been set.");
                if (!this.getUnitOfMeasureCode().equals(ridb.getUnitOfMeasureCode()))
                    this.addError("", "Unit of measure can not be updated after last generated period end date has been set.");
            }
        }

        if (this.getEffEndDate() != null && this.getEffStartDate().compareTo(this.getEffEndDate()) >= 0) {
            this.addError("effenddate", "Effective end date can not come before the start date.");
        }

    }

}

Extends our custom Model class. This will extend the actual ActiveJDBC Model class.

package com.brookdale.model.activejdbc;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.javalite.activejdbc.Model;
import org.javalite.activejdbc.validation.ValidationBuilder;
import org.javalite.activejdbc.validation.ValidatorAdapter;

import com.brookdale.core.CLArgs;
import com.brookdale.security.bo.User;

public abstract class CecilModel extends Model {

    private static final transient TypeReference<HashMap<String, Object>> mapType = new TypeReference<HashMap<String, Object>>() {};
    private static final transient TypeReference<LinkedList<HashMap<String, Object>>> listMapType = new TypeReference<LinkedList<HashMap<String, Object>>>() {};
    private static final transient SimpleDateFormat jsonDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");


    public Timestamp getUpdateDateTime() {
        return getTimestamp("updateDateTime");
    }
    public void setUpdateDateTime(LocalDateTime updateDateTime) {
        set("updateDateTime",updateDateTime == null ? null : Timestamp.valueOf(updateDateTime));
    }
    public Timestamp getCreateDateTime() {
        return getTimestamp("createDateTime");
    }
    public void setCreateDateTime(LocalDateTime createDateTime) {
        set("createDateTime",createDateTime == null ? null : Timestamp.valueOf(createDateTime));
    }
    public String getUpdateUsername() {
        return getString("updateUsername");
    }
    public void setUpdateUsername(String updateUsername) {
        set("updateUsername",updateUsername);
    }
    public String getCreateUsername() {
        return getString("createUsername");
    }
    public void setCreateUsername(String createUsername) {
        set("createUsername",createUsername);
    }
    public Long getUpdateTimeId() {
        return getLong("updateTimeId");
    }
    public void setUpdateTimeId(Long updateTimeId) {
        set("updateTimeId",updateTimeId);
    }

    public boolean save(User user) {
        String userId = (CLArgs.args.isAuthenabled()) ? user.getUserid() : "TEST_MODE";
        // insert
        java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());
        if (this.getId() == null || this.getId().toString().equals("0")) {
            this.setId(null);
            this.set("createDateTime", now);
            this.set("createUsername", userId);
            this.set("updateDateTime", now);
            this.set("updateUsername", userId);
            this.set("updateTimeId", 1);
        } 
        // update
        else {
            Long updatetimeid = this.getLong("updateTimeid");
            this.set("updateDateTime", now);
            this.set("updateUsername", userId);
            this.set("updateTimeId",  updatetimeid == null ? 1 : updatetimeid + 1);
        }
        return super.save();
    }

    public boolean saveIt(User user) {
        String userId = (CLArgs.args.isAuthenabled()) ? user.getUserid() : "TEST_MODE";
        // insert
        java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());
        if (this.isNew()) {
            this.setId(null);
            this.set("createDateTime", now);
            this.set("createUsername", userId);
            this.set("updateDateTime", now);
            this.set("updateUsername", userId);
            this.set("updateTimeId", 1);
        } 
        // update
        else {
            Long updatetimeid = this.getLong("updateTimeid");
            this.set("updateDateTime", now);
            this.set("updateUsername", userId);
            this.set("updateTimeId",  updatetimeid == null ? 1 : updatetimeid + 1);
        }
        return super.saveIt();
    }

    public boolean saveModel(User user, boolean insert) {
        if(insert){
            this.insertIt(user);
        }else{
            this.updateIt(user);
        }
        return super.saveIt();
    }

    public boolean insertIt(User user) {
        // insert
        java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());     
        this.setId(null);
        this.set("createDateTime", now);
        this.set("createUsername", user.getUserid());
        this.set("updateDateTime", now);
        this.set("updateUsername", user.getUserid());
        this.set("updateTimeId", 1);
        return super.saveIt();
    }

    public boolean updateIt(User user) {
        // insert
        java.sql.Timestamp now = java.sql.Timestamp.valueOf(java.time.LocalDateTime.now());     
        Long updatetimeid = this.getLong("updateTimeid");
        this.set("updateDateTime", now);
        this.set("updateUsername", user.getUserid());
        this.set("updateTimeId",  updatetimeid == null ? 1 : updatetimeid + 1);
        return super.saveIt();
    }

    // Convert a single ActiveJdbc Object to a json string
    @SuppressWarnings("unchecked")
    public String toJson() {
        Map<String, Object> objMap = this.toMap();
        try {
            if (objMap.containsKey("parents")) {
                Map<String, ?> parentsMap = (Map<String, ?>) objMap.get("parents");
                for (String key: parentsMap.keySet()) {
                    objMap.put(key, parentsMap.get(key));
                }
                objMap.remove("parents");
            }
            if (objMap.containsKey("children")) {
                Map<String, ?> childrenMap = (Map<String, ?>) objMap.get("children");
                for (String key: childrenMap.keySet()) {
                    objMap.put(key, childrenMap.get(key));
                }
                objMap.remove("children");
            }
            ObjectMapper mapper = new ObjectMapper();
            mapper.setDateFormat(jsonDateFormat);
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objMap);
        } catch (Exception e) { throw new RuntimeException(e); }
    }
    // Converts a single json object into an ActiveJdbc Model
    public <T extends CecilModel> T toObj(String json) {
        try {
            Map<String, Object> objMap = toMap(json);
            convertDatesToTimestamp(objMap);
            return this.fromMap(objMap);
        } catch (Exception e) { throw new RuntimeException(e); }
    }

    // STATIC CONVERTERS FOR COLLECTIONS OF OBJECTS
    // Convert an ActiveJdbc LazyList Collection to a JSON string
    public static <T extends Model> String toJson(Collection<T> objCollection) {
        //objCollection.load();
        StringBuffer json = new StringBuffer("[ ");
        for (T obj: objCollection) {
            if (CecilModel.class.isInstance(obj)) {
                json.append(((CecilModel)obj).toJson() + ",");
            } else {
                try {
                    json.append(new ObjectMapper().writeValueAsString(obj));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }
        return json.substring(0, json.length()-1) + "]";
    }
    // Converts an array of json objects into a list of ActiveJdbc Models
    public static <T extends Model> List<T> toObjList(String json, Class<T> cls) {
        List<T> results = new LinkedList<T>();
        try {
            List<Map<String, Object>> objMapList = toMaps(json);
            for (Map<String, Object> objMap: objMapList) {
                convertDatesToTimestamp(objMap);
                T obj = cls.newInstance().fromMap(objMap);
                results.add(obj);
            }
        } catch (Exception e) { throw new RuntimeException(e); } 
        return results;
    }


    // Converts a single json object into a map of key:value pairs
    private static Map<String, Object> toMap(String json) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(json, mapType);
        } catch (IOException e) { throw new RuntimeException(e); }
    }
    // Converts an array of json objects into a list of maps 
    private static List<Map<String, Object>> toMaps(String json) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(json, listMapType);
        } catch (IOException e) { throw new RuntimeException(e); } 
    }
    // checks for Strings that are formatted in 'yyyy-MM-ddTHH:mm:ss.SSSZ' format
    // if found it will replace the String value with a java.sql.Timestamp value in the objMap
    private static final Map<String,Object> convertDatesToTimestamp(Map<String, Object> objMap) {
        // attempt to convert all dates to java.sql.Timestamp
        for (String key: objMap.keySet()) {
            Object value = objMap.get(key);
            System.out.println("Checking if '" + key + "=" + (value == null ? "null" : value.toString()) +"' is a date...");
            if (value instanceof String && ((String) value).matches("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$")) {
                String valuestr = (String) value;
                System.out.println("DATE FOUND FOR '" + key + "' " + value);
                objMap.put(key, Timestamp.valueOf(ZonedDateTime.parse(valuestr).toLocalDateTime()));
            }
        }
        return objMap;
    }

    public static ValidationBuilder<?> validateAbsenceOf(String ... attributes) {
        return validateWith(new ValidatorAdapter() {

            @Override
            public void validate(Model m) {
                boolean containsAttribute = false;

                for(String attribute:attributes) {

                    if(m.attributeNames().contains(attribute)) {
                        //model contains attribute, invalidate now !
                        m.addValidator(this, attribute);
                        break;
                    }
                }
            }
        });
    }
}

Our Controller

package com.brookdale.controller;

import static spark.Spark.get;
import static spark.Spark.post;
import static spark.Spark.put;

import org.codehaus.jackson.map.ObjectMapper;

import com.brookdale.model.RecurringItem;
import com.brookdale.model.activejdbc.CecilModel;
import com.brookdale.security.bo.User;
import com.brookdale.service.RecurringItemService;

public class RecurringItemController {

    public RecurringItemController(final RecurringItemService service) {
        // get list of recurring items based on the agreementid
        get("/api/recurring/list/:agreementid", (req,res)-> { 
            String all = req.queryParams("all");
            Long agreementid = Long.parseLong(req.params(":agreementid"));
            //return RecurringItemAPI.searchByAgreement(Long.parseLong(req.params(":agreementid"))).toJson(true); 
            return CecilModel.toJson(service.findByAgreementId(agreementid, all != null)); 

        });
        // insert
        post("/api/recurring/save", (req,res)-> { 
            //RecurringItem ri = ActiveJdbcJson.toObj(req.body(), RecurringItem.class);
            RecurringItem ri = new RecurringItem().toObj(req.body());
            // set unitqty to '1' since the field is not nullable, but not used
            if (ri.getUnitQty() == null)
                ri.setUnitQty(1);
            System.out.println("ri to insert: " + new ObjectMapper().writeValueAsString(ri));
            return service.saveRecurringItem(ri, (User) req.attribute("user")).toJson(); 
        });
        // update
        put("/api/recurring/save", (req,res)-> { 
            //RecurringItem ri = ActiveJdbcJson.toObj(req.body(), RecurringItem.class);
            RecurringItem ri = new RecurringItem().toObj(req.body());
            System.out.println("ri to update: " + new ObjectMapper().writeValueAsString(ri));
            return service.saveRecurringItem(ri, (User) req.attribute("user")).toJson(); 
        });

    }

}

Which calls our service layer to do the save.

package com.brookdale.service;

import org.javalite.activejdbc.LazyList;
import org.javalite.activejdbc.Model;

import com.brookdale.model.RecurringItem;
import com.brookdale.security.bo.User;

public class RecurringItemService {

    public RecurringItemService() { }

    public LazyList<Model> findByAgreementId(Long agreementId, boolean includeAll) {
        if (includeAll)
            return RecurringItem.find("contactAgreementID = ?", agreementId).orderBy("effstartdate desc");
        else
            return RecurringItem.find("contactAgreementID = ? and effenddate is null", agreementId).orderBy("effstartdate desc");
    }
    public RecurringItem saveRecurringItem(RecurringItem ri, User user) {
        ri.saveIt(user);
        return ri;
    }

}
Jeff Moreau
  • 29
  • 1
  • 7