2

I am working on inserting CSV records to Salesforce. I usually do using Bulk API where the types are auto detected and mapped. However, I got into a scenario where I have to upload Documents or Attachments. This below code is what I am trying. Am I going in the right direction?

I have stumbled upon a scenario where the string value is set under record.setField(..). This threw the error value not of required type which expects it to be of the same type of Salesforce object. How can I map the Salesforce Object's type from CSV? Note that I already hold the sObject's details (field, fieldtypes, soaptypes).

I am sure that there could be another way without manually establishing a mapping between Salesforce types and java types (e.g. boolean, but date cannot be done since it is of ISO format).

REST API does accept a json which auto maps the field types. Is there a way that this could be done automatically using SOAP API's Partner jar?

int batchSize = 200;
int bodyIdx = 0;
List<String> keys = new ArrayList<>(ids.keySet());
Path fileDir = SalesforceOptions.restoreFolder.resolve(sObject.getName());
Set<String> binaryFields = new HashSet<>(sObject.getBinaryFields());
List<SObject> records = new ArrayList<>();
String sObjname = sObject.getName();
String bodyField = SalesforceUtility.docFields(sObject).getContent();
// Read the CSV file
try (BufferedReader reader = Files.newBufferedReader(Paths.get(csvPath), StandardCharsets.UTF_8);)
{
    // Take a note of the header to keep track of binary field index
    CSVRecord header = null;
    for (CSVRecord csvRecord : CSVFormat.DEFAULT.withRecordSeparator(System.lineSeparator())
            .withQuoteMode(QuoteMode.ALL).parse(reader))
    {
        if (csvRecord.getRecordNumber() == 1)
        {
            header = csvRecord;
            for (int j = 0; j < header.size(); j++)
            {
                if (header.get(j).equals(bodyField))
                {
                    bodyIdx = j;
                    break;
                }
            }
            continue;
        }

        // Had a logic to put '#' in bulk, undo it; Get the file name
        String fileName = csvRecord.get(bodyIdx).replaceFirst("#", "");
        Path filePath = fileDir.resolve(fileName);
        long fileSize = filePath.toFile().length();

        // Record structure
        SObject record = new SObject();
        // Set the object type
        record.setType(sObject.getName());
        for (int i = 0; i < header.size(); i++)
        {
            String fieldName = header.get(i);
            if (sObject.hasBinaryfield() && binaryFields.contains(fieldName))
                record.setField(fieldName, Base64.getEncoder().encode(Files.readAllBytes(filePath)));
            else
            {
                // FIXME: Probable issue where the field being set is String type
                record.setField(fieldName, csvRecord.get(i));
            }
        }
        records.add(record);

        if (records.size() % batchSize == 0)
        {
            if (operationType == OperationEnum.insert)
                insert(sObject, records, keys);
            else
                update(sObject, records, keys);
            records.clear();
        }
    }

    if (!records.isEmpty())
    {
        if (operationType == OperationEnum.insert)
            insert(sObject, records, keys);
        else
            update(sObject, records, keys);
    }
}
2
  • Can you isolate the problem field and value from the CSV you are passing in? I suspect the problem is around data types. E.g. the field will be a Date in Salesforce, but the string you are passing in from the CSV isn't in the correct format. May 25, 2016 at 23:42
  • I am able to single out a field or two. For example, Attachment contains IsPrivate(boolean). If I fix this, error occurs in another field. I would like to stay away from writing code that is too specific to a particular object. However, if I have to generalize for different objects and with custom ones, I'd like to know how this is feasible. Regarding the Date field, the string is in ISO format; can be converted. The moot point is how can a similar thing be done for all the data types?
    – dmachop
    May 26, 2016 at 0:08

2 Answers 2

0

Since it appears the problem is with the formatting of the input data to match the Salesforce expected data types for each field, I'd suggest accessing the sObject metadata via describeSObjects(). From the DescribeSObjectResult you can drill into the fields collection and corresponding type FieldType property. I.e., given a field name, is it a string/boolean/int/date.

From there you can format the input CSV data into the format that Salesforce expects for that data type.

0

As I have already mentioned that I do have the types of every field, for every field, the utility class should convert Salesforce's Type to Java type. This is the primitive idea (not a working code) of how the utility would look like:

public Object castSFtoJavaType(String value, FieldType field)
{
    // Get type mapper to get class to cast to
    Class clazz = getJavaType(...);
    return (clazz) value;
}

I have come up with utilizing the TypeMapper class in web service connector jar. This is what is required for mapping Salesforce's types to Java types and vice-versa.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .