11

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.

4
  • 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. Commented Jul 4, 2018 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
    Commented Jul 4, 2018 at 17:55
  • I agree that it seems inappropriate here, maybe someone can find an actual justification from Salesforce. Commented Jul 4, 2018 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
    Commented Jul 4, 2018 at 18:10

2 Answers 2

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;
}
5
  • Thanks David, I'd already found your code and will give it a go.
    – Keith C
    Commented Jul 4, 2018 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
    Commented Jul 4, 2018 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
    Commented Jul 4, 2018 at 12:35
  • That is very interesting. If you find a solution, please post! I'd love to see what works.
    – David Reed
    Commented Jul 4, 2018 at 12:49
  • See my answer for the escaping that is appropriate in my case.
    – Keith C
    Commented Jul 4, 2018 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;
}
1
  • 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
    Commented Jul 4, 2018 at 19:39

You must log in to answer this question.

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