<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<base href="https://hibernate.atlassian.net">
<title>Message Title</title>
</head>
<body class="jira" style="color: #333333; font-family: Arial, sans-serif; font-size: 14px; line-height: 1.429">
<table id="background-table" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0; background-color: #f5f5f5; border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0" bgcolor="#f5f5f5">
<!-- header here -->
<tbody>
<tr>
<td id="header-pattern-container" style="padding: 0; border-collapse: collapse; padding: 10px 20px">
<table id="header-pattern" cellspacing="0" cellpadding="0" border="0" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0">
<tbody>
<tr>
<td id="header-avatar-image-container" valign="top" style="padding: 0; border-collapse: collapse; vertical-align: top; width: 32px; padding-right: 8px" width="32"> <img id="header-avatar-image" class="image_fix" src="cid:jira-generated-image-avatar-42ae9f53-fd07-41fb-8027-d6b1ec52470e" height="32" width="32" border="0" style="border-radius: 3px; vertical-align: top"> </td>
<td id="header-text-container" valign="middle" style="padding: 0; border-collapse: collapse; vertical-align: middle; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px"> <a class="user-hover" rel="crancran" id="email_crancran" href="https://hibernate.atlassian.net/secure/ViewProfile.jspa?name=crancran" style="color:#6c797f;; color: #3b73af; text-decoration: none">Chris Cranford</a> <strong>commented</strong> on <a href="https://hibernate.atlassian.net/browse/HHH-7940" style="color: #3b73af; text-decoration: none"><img src="cid:jira-generated-image-avatar-09a1663c-ac2a-467f-8ac8-0e7fc70abc8e" height="16" width="16" border="0" align="absmiddle" alt="Bug"> HHH-7940</a> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td id="email-content-container" style="padding: 0; border-collapse: collapse; padding: 0 20px">
<table id="email-content-table" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0; border-spacing: 0; border-collapse: separate">
<tbody>
<tr>
<!-- there needs to be content in the cell for it to render in some clients -->
<td class="email-content-rounded-top mobile-expand" style="padding: 0; border-collapse: collapse; color: #ffffff; padding: 0 15px 0 16px; height: 15px; background-color: #ffffff; border-left: 1px solid #cccccc; border-top: 1px solid #cccccc; border-right: 1px solid #cccccc; border-bottom: 0; border-top-right-radius: 5px; border-top-left-radius: 5px; height: 10px; line-height: 10px; padding: 0 15px 0 16px; mso-line-height-rule: exactly" height="10" bgcolor="#ffffff"> </td>
</tr>
<tr>
<td class="email-content-main mobile-expand " style="padding: 0; border-collapse: collapse; border-left: 1px solid #cccccc; border-right: 1px solid #cccccc; border-top: 0; border-bottom: 0; padding: 0 15px 0 16px; background-color: #ffffff" bgcolor="#ffffff">
<table class="page-title-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0">
<tbody>
<tr>
<td style="vertical-align: top;; padding: 0; border-collapse: collapse; padding-right: 5px; font-size: 20px; line-height: 30px; mso-line-height-rule: exactly" class="page-title-pattern-header-container"> <span class="page-title-pattern-header" style="font-family: Arial, sans-serif; padding: 0; font-size: 20px; line-height: 30px; mso-text-raise: 2px; mso-line-height-rule: exactly; vertical-align: middle"> <a href="https://hibernate.atlassian.net/browse/HHH-7940" style="color: #3b73af; text-decoration: none">Re: NullPointerException with indexed Collections</a> </span> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td id="text-paragraph-pattern-top" class="email-content-main mobile-expand comment-top-pattern" style="padding: 0; border-collapse: collapse; border-left: 1px solid #cccccc; border-right: 1px solid #cccccc; border-top: 0; border-bottom: 0; padding: 0 15px 0 16px; background-color: #ffffff; border-bottom: none; padding-bottom: 0" bgcolor="#ffffff">
<table class="text-paragraph-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 2px">
<tbody>
<tr>
<td class="text-paragraph-pattern-container mobile-resize-text " style="padding: 0; border-collapse: collapse; padding: 0 0 10px"> <p style="margin: 10px 0 0; margin-top: 0">The <tt>NullPointerException</tt> is because your mappings are not correct from an Envers perspective. </p> <p style="margin: 10px 0 0">You have two options:</p> <p style="margin: 10px 0 0"><b><ins>Join Table</ins></b><br> The relationship as you have it defined doesn't use a join table, but instead relies on placing the joining attributes inline on the <tt>@ManyToOne</tt> side. If you were to change the <tt>@OneToMany</tt> mapping not to use <tt>mappedBy</tt>, a join table would be used by Hibernate and Envers instead. When you use this approach, its worth noting that the tests as you have them coded will validate correctly, see below why I mention this.</p> <p style="margin: 10px 0 0"><b><ins>No Join Table</ins></b><br> In order to not use a join table, we'll need to leverage a few more Envers annotations and be explicit about the column join mappings. You're welcomed to look at this commit (<a href="https://github.com/Naros/hibernate-orm/commit/21f23fed81313af3853228173767d88ac83e7390" class="external-link" rel="nofollow" style="color: #3b73af; text-decoration: none">https://github.com/Naros/hibernate-orm/commit/21f23fed81313af3853228173767d88ac83e7390</a>) for reference. </p> <p style="margin: 10px 0 0">One important point to note is that the <tt>@OneToMany</tt> must be mapped as follows:</p>
<div class="code panel" style="border-width: 1px;; border: 1px solid #cccccc; background: #f5f5f5; font-size: 12px; line-height: 1.333; font-family: monospace; border: 1px solid #cccccc; -moz-border-radius: 3px; border-radius: 3px; margin: 9px 0">
<div class="codeContent panelContent" style="padding: 9px 12px">
<pre class="code-java" style="margin: 10px 0 0; margin-top: 0; max-height: 30em; overflow: auto; white-space: pre-wrap; word-wrap: normal">
@OneToMany
@OrderColumn(name = <span class="code-quote" style="color: #009100">"indexed_index"</span>)
@JoinColumn(name = <span class="code-quote" style="color: #009100">"indexed_join_column"</span>)
@AuditMappedBy(mappedBy = <span class="code-quote" style="color: #009100">"reference"</span>, positionMappedBy = <span class="code-quote" style="color: #009100">"position"</span>)
<span class="code-keyword" style="color: #000091">private</span> List<IndexedListRefIngEntity> referring = <span class="code-keyword" style="color: #000091">new</span> ArrayList<>();
</pre>
</div>
</div> <p style="margin: 10px 0 0">I removed the <tt>mappedBy</tt> from the <tt>@OneToMany</tt> because you want to allow the <tt>@AuditMappedBy</tt> to influence the mapping. If the <tt>mappedBy</tt> remained on the <tt>@OneToMany</tt>, the <tt>@AuditMappedBy</tt> annotation would have been ignored preventing Envers to know where the position is mapped for the <tt>@OrderColumn</tt>. But in order to not use a join-table and with <tt>mappedBy</tt> not being used on the <tt>@OneToMany</tt>, a <tt>@JoinColumn</tt> must be specified to explicitly map the relation join.</p> <p style="margin: 10px 0 0">On the <tt>@ManyToOne</tt> side, I needed to change its mapping and also add a new property:</p>
<div class="code panel" style="border-width: 1px;; border: 1px solid #cccccc; background: #f5f5f5; font-size: 12px; line-height: 1.333; font-family: monospace; border: 1px solid #cccccc; -moz-border-radius: 3px; border-radius: 3px; margin: 9px 0">
<div class="codeContent panelContent" style="padding: 9px 12px">
<pre class="code-java" style="margin: 10px 0 0; margin-top: 0; max-height: 30em; overflow: auto; white-space: pre-wrap; word-wrap: normal">
@ManyToOne
@JoinColumn(name = <span class="code-quote" style="color: #009100">"indexed_join_column"</span>, insertable = <span class="code-keyword" style="color: #000091">false</span>, updatable = <span class="code-keyword" style="color: #000091">false</span>)
<span class="code-keyword" style="color: #000091">private</span> IndexedListRefEdEntity reference;
@Column(name = <span class="code-quote" style="color: #009100">"indexed_index"</span>, insertable = <span class="code-keyword" style="color: #000091">false</span>, updatable = <span class="code-keyword" style="color: #000091">false</span>)
<span class="code-keyword" style="color: #000091">private</span> <span class="code-object" style="color: #910091">Integer</span> position;
</pre>
</div>
</div> <p style="margin: 10px 0 0">Here you'll notice I added a <tt>@JoinColumn</tt> on the <tt>@ManyToOne</tt> for the same reasons as the <tt>@OneToMany</tt>. But Envers needs the collection-side to be the <b>owner</b> to manage proper auditing, and so the <tt>@JoinColumn</tt> is non-insertable and non-updatable. Additionally, I added a new property, <em>position</em>, that is a place holder for the <tt>@OrderColumn</tt> / <tt>@IndexColumn</tt> value specified by the <tt>@AuditMappedBy</tt> annotation on the opposite side of this relation. This field should be mapped as non-insertable and non-updatable to prevent user code from changing this value. It's essentially here to give Enver's visibility to this column, nothing more.</p> <p style="margin: 10px 0 0">It's worth noting that the column name given to the <em>position</em> property should match the name given to the <tt>@OrderColumn</tt> / <tt>@IndexColumn</tt> on the other side of the mapping. This is so that the right column is being read/maintained from both Envers and Hibernate for the collection index.</p> <p style="margin: 10px 0 0">The caveat here though is that Hibernate will generate a slightly different audit trail for this configuration. More specifically, you'll notice in the <tt>testRevisionsCounts()</tt> test, the last assertion is <b>(1,2,3)</b> rather than <b>(1,3)</b>. This is due to the removal of an entity in the collection causing the remaining entity's index to change during Revision 2.</p> <p style="margin: 10px 0 0">With that said...</p> <p style="margin: 10px 0 0">I do think I'd like to investigate what would be necessary to improve the mapping necessary to build this type of an audit relationship. If possible, I'd prefer to see the mappings just as your test case originally had them and Envers being able to build it's internal model as necessary from it without any other annotations. I can't be certain what impacts that may have, specifically that Envers wants the ownership of the relation on the collection-side whereas your test case made that be the non-collection-side.</p> <p style="margin: 10px 0 0">I think what we need to do is at the very least here is to present the use with a <tt>MappingException</tt> while building the Envers model. This prevents this downstream <tt>NullPointerException</tt> and gives the user a bit of guidance on what may be wrong with their mappings.</p> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td class="email-content-main mobile-expand " style="padding: 0; border-collapse: collapse; border-left: 1px solid #cccccc; border-right: 1px solid #cccccc; border-top: 0; border-bottom: 0; padding: 0 15px 0 16px; background-color: #ffffff" bgcolor="#ffffff">
<table id="actions-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px">
<tbody>
<tr>
<td id="actions-pattern-container" valign="middle" style="padding: 0; border-collapse: collapse; padding: 10px 0 10px 24px; vertical-align: middle; padding-left: 0">
<table align="left" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0">
<tbody>
<tr>
<td class="actions-pattern-action-icon-container" style="padding: 0; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 0; vertical-align: middle"> <a href="https://hibernate.atlassian.net/browse/HHH-7940#add-comment" target="_blank" title="Add Comment" style="color: #3b73af; text-decoration: none"> <img class="actions-pattern-action-icon-image" src="cid:jira-generated-image-static-comment-icon-d46ee645-f426-4f88-9d95-1b275ee75428" alt="Add Comment" title="Add Comment" height="16" width="16" border="0" style="vertical-align: middle"> </a> </td>
<td class="actions-pattern-action-text-container" style="padding: 0; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; padding-left: 5px"> <a href="https://hibernate.atlassian.net/browse/HHH-7940#add-comment" target="_blank" title="Add Comment" style="color: #3b73af; text-decoration: none">Add Comment</a> </td>
</tr>
</tbody>
</table> </td>
</tr>
</tbody>
</table> </td>
</tr>
<!-- there needs to be content in the cell for it to render in some clients -->
<tr>
<td class="email-content-rounded-bottom mobile-expand" style="padding: 0; border-collapse: collapse; color: #ffffff; padding: 0 15px 0 16px; height: 5px; line-height: 5px; background-color: #ffffff; border-top: 0; border-left: 1px solid #cccccc; border-bottom: 1px solid #cccccc; border-right: 1px solid #cccccc; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; mso-line-height-rule: exactly" height="5" bgcolor="#ffffff"> </td>
</tr>
</tbody>
</table> </td>
</tr>
<tr>
<td id="footer-pattern" style="padding: 0; border-collapse: collapse; padding: 12px 20px">
<table id="footer-pattern-container" cellspacing="0" cellpadding="0" border="0" style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0">
<tbody>
<tr>
<td id="footer-pattern-text" class="mobile-resize-text" width="100%" style="padding: 0; border-collapse: collapse; color: #999999; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px"> This message was sent by Atlassian JIRA <span id="footer-build-information">(v1000.184.1#100008-<span title="1fb1cc9d7843d715cb5c8659dca05d9b0372565f" data-commit-id="1fb1cc9d7843d715cb5c8659dca05d9b0372565f}">sha1:1fb1cc9</span>)</span> </td>
<td id="footer-pattern-logo-desktop-container" valign="top" style="padding: 0; border-collapse: collapse; padding-left: 20px; vertical-align: top">
<table style="border-collapse: collapse; mso-table-lspace: 0; mso-table-rspace: 0">
<tbody>
<tr>
<td id="footer-pattern-logo-desktop-padding" style="padding: 0; border-collapse: collapse; padding-top: 3px"> <img id="footer-pattern-logo-desktop" src="cid:jira-generated-image-static-footer-desktop-logo-fb14c891-3bd7-4c87-8567-d887814dbd52" alt="Atlassian logo" title="Atlassian logo" width="169" height="36" class="image_fix"> </td>
</tr>
</tbody>
</table> </td>
</tr>
</tbody>
</table> </td>
</tr>
</tbody>
</table>
</body>
</html>