9

My specific questions are (for the below detail):

  1. Anyone have any idea why the design is like this?
  2. Is the only solution to always clean the content perfectly before saving it?

This type is not mentioned in Exception Class and Built-In Exceptions (that does mention that governor limit LimitException can't be caught) and this code compiles:

    try {
        // Update some ContentNote objects
    } catch (DmlException e) {
        ApexPages.addMessages(e);
    } catch (UnexpectedException e) {
        ApexPages.addMessages(e);   
    }

but when it runs and the update throws an UnexpectedException with the message:

Note can't be saved because it contains HTML tags or unescaped characters that are not allowed in a Note.

the catch of UnexpectedException doesn't work.

  • This is just my opinion, but as far as I can tell UnexpectedException is supposed to be thrown when you do something Salesforce wants to force you to stop doing, like calling the Object constructor. Maybe they want to stop developers from putting unescaped user input into notes. – IllusiveBrian Jul 4 '18 at 17:45
  • @IllusiveBrian Throwing exceptions is fine, but making them uncatchable means a user is going to get a pretty nasty white screen error rather than the code being able to recover or present a reasonable ApexPages message. – Keith C Jul 4 '18 at 17:55
  • I agree that it seems inappropriate here, maybe someone can find an actual justification from Salesforce. – IllusiveBrian Jul 4 '18 at 17:58
  • @IllusiveBrian That was what I was asking in the first place; moved the 2 questions to the top to make that a bit clearer. – Keith C Jul 4 '18 at 18:10
11

System.UnexpectedException gets thrown a lot with Note inserts if you do not prepare the content exactly right, and they cannot be caught or handled in any way.

I wrote an open source package a while ago to abstract over some of these issues. From its documentation, a summary of the requirements:

The following steps are required to prepare note content for insertion into Salesforce:

  1. Replace all basic HTML characters (<>"'&) with their corresponding entities (&amp; and friends).
  2. Replace all line breaks with <br> (taking care with Windows CRLF/Linux LF/Mac CR)
  3. Replace &apos; with &#39;.
  4. Do not replace Unicode characters with entities. Other entities, including &apos;, result in an exception. Unicode should be left as the bare characters.
  5. Ensure that the source content is well-formed Unicode/UTF-8 and does not contain non-printable characters.
  6. The title must not be null, zero-length, or consist only of whitespace. The title need not be escaped.

So while I don't have an answer to (1), the answer to (2) is "yes."

The skeleton of the code that I worked out to avoid the issue looks like this:

public void addNote(String title, String content, Id linkedTo, String visibility, String shareType) {
    ContentNote cn = new ContentNote();

    if (title != null && title.normalizeSpace().length() > 0) {
        // A null, zero-length, or all-whitespace title will result in an UnexpectedException on insert.
        cn.Title = title;
    } else {
        cn.Title = 'Untitled Note';
    }

    cn.Content = Blob.valueOf(content.escapeXML().replace('\r\n', '<br>').replace('\r', '<br>').replace('\n', '<br>').replace('&apos;', '&#39;'));

    insert cn;

    ContentDocumentLink cdl = new ContentDocumentLink();

    cdl.ContentDocumentId = cn.Id;
    cdl.LinkedEntityId = linkedTo;
    cdl.Visibility = visibility;
    cdl.ShareType = shareType;

    insert cdl;
}
  • Thanks David, I'd already found your code and will give it a go. – Keith C Jul 4 '18 at 12:31
  • It's been a while since I looked at it. If you find anything screwy or no longer kosher, please let me know! – David Reed Jul 4 '18 at 12:32
  • Thanks! My case is a bit difference in that I want to preserve the HTML tags as the content is being edited as HTML through a CKEditor instance. Will see what set of replaces work for that case. – Keith C Jul 4 '18 at 12:35
  • That is very interesting. If you find a solution, please post! I'd love to see what works. – David Reed Jul 4 '18 at 12:49
  • See my answer for the escaping that is appropriate in my case. – Keith C Jul 4 '18 at 17:56
2

Still interested in an answer to question 1. Assuming the answer to question 2 is "yes" I've come up with the following for my case - FYI for anyone looking for an answer to the follow up question of "how".

I am using CKEditor to produce HTML that I want to save in a Content Note. There appears to be no reason to escape all the XML and based on a dozen or so unit test cases and some large example HTML pasted interactively, this seems to be sufficient:

// Apply this before saving
private static String sanitize(String s) {
    return s != null ? s.trim().replace('&', '&amp;') : null;
}

// Apply this after loading
private static String unsanitize(String s) {
    return s != null ? s.replace('&amp;', '&') : null;
}
  • Does it still throw an exception if you have HTML entities like &apos; or those for Unicode characters in your content (used to; wondering if that behavior's changed)? – David Reed Jul 4 '18 at 19:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.