{"action":"created","comment":{"url":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/comments/27569130","id":27569130,"diff_hunk":"@@ -3446,11 +3457,148 @@ public void readObjectsFromForm(EditForm eform, XWikiContext context) throws XWi\n         }\n     }\n \n+    /**\n+     * Generate a map from the request parameters of the form '<spacename>.<classname>_<number>_<propertyname>' Keys of\n+     * this map will be the reference '<spacename>.<classname>' to the Class (for example, 'XWiki.XWikiRights'), the\n+     * content is a list where each element describe property for the object <number>. Element of the list is a map\n+     * where key is <propertyname> and content is the array of corresponding values. Example with a list of HTTP\n+     * parameters:\n+     * <ul>\n+     * <li>XWiki.XWikiRights_0_users=XWiki.Admin</li>\n+     * <li>XWiki.XWikiRights_0_users=XWiki.Me</li>\n+     * <li>XWiki.XWikiRights_0_groups=XWiki.XWikiAllGroup</li>\n+     * <li>XWiki.XWikiRights_1_user=XWiki.Admin</li>\n+     * <li>XWiki.XWikiUsers_1_name=Spirou</li>\n+     * </ul>\n+     * will result in the following map <code><pre>\n+     * {\n+     *   \"XWiki.XWikiRights\": {\n+     *     \"0\": {\n+     *       \"users\": [\"XWiki.Admin\", \"XWiki.Me\"],\n+     *       \"groups\": [\"XWiki.XWikiAllGroup\"]\n+     *     },\n+     *     \"1\": {\n+     *       \"users\": [\"XWiki.Admin\"]\n+     *     }\n+     *   ],\n+     *   \"XWiki.XWikiUsers\": \n+     *     \"1\": {\n+     *       \"name\": [\"Spirou\"]\n+     *     }\n+     *   ]\n+     * }\n+     * </pre></code>\n+     * \n+     * @param request is the input HTTP request that provides the parameters\n+     * @param context\n+     * @return a map containing ordered data\n+     */\n+    private Map<DocumentReference, SortedMap<Integer, Map<String, String[]>>> parseRequestUpdateOrCreate(XWikiRequest request,\n+        XWikiContext context)\n+    {\n+        Map<DocumentReference, SortedMap<Integer, Map<String, String[]>>> result = new HashMap<>();\n+        @SuppressWarnings(\"unchecked\")\n+        Map<String, String[]> allParameters = request.getParameterMap();\n+        for (Entry<String, String[]> parameter : allParameters.entrySet()) {\n+            Matcher matcher = XPROPERTY_REFERENCE_PATTERN.matcher(parameter.getKey());\n+            if (matcher.matches() == false) {\n+                continue;\n+            }\n+            Integer classNumber;\n+            String className= matcher.group(1);\n+            String classNumberAsString = matcher.group(2);\n+            String classPropertyName = matcher.group(3);\n+            DocumentReference classReference = getCurrentDocumentReferenceResolver().resolve(className);\n+            try {\n+                BaseClass xClass = context.getWiki().getDocument(classReference, context).getXClass();\n+                if (xClass.getPropertyList().contains(classPropertyName) == false) {\n+                    continue;\n+                }\n+                classNumber = Integer.parseInt(classNumberAsString);\n+            } catch (XWikiException e) {\n+                // If the class page cannot be found, skip the property update\n+                LOGGER.warn(\"Failed to load document [{}], ignoring property update [{}]. Reason: [{}]\",\n+                    classReference, parameter.getKey(), ExceptionUtils.getRootCauseMessage(e));\n+                continue;\n+            } catch (NumberFormatException e) {\n+                // If the numner isn't valid, skip the property update\n+                LOGGER.warn(\"Invalid xobject number [{}], ignoring property update [{}].\", classNumberAsString,\n+                    parameter.getKey());\n+                continue;\n+            }\n+            SortedMap<Integer, Map<String, String[]>> objectMap = result.get(classReference);\n+            if (objectMap == null) {\n+                objectMap = new TreeMap<>();\n+                result.put(classReference, objectMap);\n+            }\n+            // Get the property from the right object #objectNumber of type 'objectName'; create it if they don't exist\n+            Map<String, String[]> object = objectMap.get(classNumber);\n+            if (object == null) {\n+                object = new HashMap<>();\n+                objectMap.put(classNumber, object);\n+            }\n+            object.put(classPropertyName, parameter.getValue());\n+        }\n+        return result;\n+    }\n+\n+    /**\n+     * Create and/or update objects in a document given a list of HTTP parameters of the form\n+     * '<spacename>.<classname>_<number>_<propertyname>'. If the object already exists, the field is replace by the\n+     * given value. If the object doesn't exist in the document, it is created then the property <propertyname> is\n+     * initialized with the given value. An object is only created if the given '<number>' is 'one-more' than the\n+     * existing number of objects. For example, if the document already has 2 objects of type 'Space.Class', then it\n+     * will create a new object only with 'Space.Class_2_prop=something'. Every other parameter like\n+     * 'Space.Class_42_prop=foobar' for example, will be ignore.\n+     * \n+     * @param eform is form information that contains all the query parameters\n+     * @param context\n+     * @throws XWikiException\n+     * @since 7.0RC1\n+     */\n+    public void readObjectsFromFormUpdateOrCreate(EditForm eform, XWikiContext context) throws XWikiException\n+    {\n+        Map<DocumentReference, SortedMap<Integer, Map<String, String[]>>> fromRequest =\n+            parseRequestUpdateOrCreate(eform.getRequest(), context);\n+        for (Entry<DocumentReference, SortedMap<Integer, Map<String, String[]>>> requestClassEntries : fromRequest\n+            .entrySet()) {\n+            DocumentReference requestClassReference = requestClassEntries.getKey();\n+            SortedMap<Integer, Map<String, String[]>> requestObjectMap = requestClassEntries.getValue();\n+            List<BaseObject> newObjects = new ArrayList<>();\n+            for (Entry<Integer, Map<String, String[]>> requestObjectEntry : requestObjectMap.entrySet()) {\n+                Integer requestObjectNumber = requestObjectEntry.getKey();\n+                Map<String, String[]> requestObjectPropertyMap = requestObjectEntry.getValue();\n+                BaseObject oldObject = getXObject(requestClassReference, requestObjectNumber);\n+                if (oldObject == null) {\n+                    // Create the object only if it has been numbered one more than the number of existing objects\n+                    if (requestObjectPropertyMap != null\n+                        && requestObjectNumber == getXObjectSize(requestClassReference)) {","path":"xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java","position":159,"original_position":159,"commit_id":"a543ab64794cec8c031f457767baf715e59e299f","original_commit_id":"a543ab64794cec8c031f457767baf715e59e299f","user":{"login":"woshilapin","id":2520723,"avatar_url":"https://avatars.githubusercontent.com/u/2520723?v=3","gravatar_id":"","url":"https://api.github.com/users/woshilapin","html_url":"https://github.com/woshilapin","followers_url":"https://api.github.com/users/woshilapin/followers","following_url":"https://api.github.com/users/woshilapin/following{/other_user}","gists_url":"https://api.github.com/users/woshilapin/gists{/gist_id}","starred_url":"https://api.github.com/users/woshilapin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/woshilapin/subscriptions","organizations_url":"https://api.github.com/users/woshilapin/orgs","repos_url":"https://api.github.com/users/woshilapin/repos","events_url":"https://api.github.com/users/woshilapin/events{/privacy}","received_events_url":"https://api.github.com/users/woshilapin/received_events","type":"User","site_admin":false},"body":"My choice is based on the answer to this question: \"what will you do if there is no object in the wiki page and your client gives you something like `XWiki.XWikiRights_42_levels`?\".  You should create 42 objects only for one useful object?  That's the reason I made this choice.  I kind of force the developer to know what he's doing.  It's only a limitation, may be improved in a later PR?","created_at":"2015-04-01T13:37:07Z","updated_at":"2015-04-01T13:37:07Z","html_url":"https://github.com/xwiki/xwiki-platform/pull/271#discussion_r27569130","pull_request_url":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271","_links":{"self":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/comments/27569130"},"html":{"href":"https://github.com/xwiki/xwiki-platform/pull/271#discussion_r27569130"},"pull_request":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271"}}},"pull_request":{"url":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271","id":14760056,"html_url":"https://github.com/xwiki/xwiki-platform/pull/271","diff_url":"https://github.com/xwiki/xwiki-platform/pull/271.diff","patch_url":"https://github.com/xwiki/xwiki-platform/pull/271.patch","issue_url":"https://api.github.com/repos/xwiki/xwiki-platform/issues/271","number":271,"state":"open","locked":false,"title":"XWIKI-10252: Add and/or edit objects in a page","user":{"login":"woshilapin","id":2520723,"avatar_url":"https://avatars.githubusercontent.com/u/2520723?v=3","gravatar_id":"","url":"https://api.github.com/users/woshilapin","html_url":"https://github.com/woshilapin","followers_url":"https://api.github.com/users/woshilapin/followers","following_url":"https://api.github.com/users/woshilapin/following{/other_user}","gists_url":"https://api.github.com/users/woshilapin/gists{/gist_id}","starred_url":"https://api.github.com/users/woshilapin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/woshilapin/subscriptions","organizations_url":"https://api.github.com/users/woshilapin/orgs","repos_url":"https://api.github.com/users/woshilapin/repos","events_url":"https://api.github.com/users/woshilapin/events{/privacy}","received_events_url":"https://api.github.com/users/woshilapin/received_events","type":"User","site_admin":false},"body":"* Provide a new object policy to edit but also create new objects in on step","created_at":"2014-04-15T09:16:41Z","updated_at":"2015-04-01T13:37:07Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fa79c0dbb2bc0a97e92923d9739443caa8268f8e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271/commits","review_comments_url":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271/comments","review_comment_url":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/comments{/number}","comments_url":"https://api.github.com/repos/xwiki/xwiki-platform/issues/271/comments","statuses_url":"https://api.github.com/repos/xwiki/xwiki-platform/statuses/a543ab64794cec8c031f457767baf715e59e299f","head":{"label":"woshilapin:object-policy","ref":"object-policy","sha":"a543ab64794cec8c031f457767baf715e59e299f","user":{"login":"woshilapin","id":2520723,"avatar_url":"https://avatars.githubusercontent.com/u/2520723?v=3","gravatar_id":"","url":"https://api.github.com/users/woshilapin","html_url":"https://github.com/woshilapin","followers_url":"https://api.github.com/users/woshilapin/followers","following_url":"https://api.github.com/users/woshilapin/following{/other_user}","gists_url":"https://api.github.com/users/woshilapin/gists{/gist_id}","starred_url":"https://api.github.com/users/woshilapin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/woshilapin/subscriptions","organizations_url":"https://api.github.com/users/woshilapin/orgs","repos_url":"https://api.github.com/users/woshilapin/repos","events_url":"https://api.github.com/users/woshilapin/events{/privacy}","received_events_url":"https://api.github.com/users/woshilapin/received_events","type":"User","site_admin":false},"repo":{"id":15105092,"name":"xwiki-platform","full_name":"woshilapin/xwiki-platform","owner":{"login":"woshilapin","id":2520723,"avatar_url":"https://avatars.githubusercontent.com/u/2520723?v=3","gravatar_id":"","url":"https://api.github.com/users/woshilapin","html_url":"https://github.com/woshilapin","followers_url":"https://api.github.com/users/woshilapin/followers","following_url":"https://api.github.com/users/woshilapin/following{/other_user}","gists_url":"https://api.github.com/users/woshilapin/gists{/gist_id}","starred_url":"https://api.github.com/users/woshilapin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/woshilapin/subscriptions","organizations_url":"https://api.github.com/users/woshilapin/orgs","repos_url":"https://api.github.com/users/woshilapin/repos","events_url":"https://api.github.com/users/woshilapin/events{/privacy}","received_events_url":"https://api.github.com/users/woshilapin/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/woshilapin/xwiki-platform","description":"The XWiki platform","fork":true,"url":"https://api.github.com/repos/woshilapin/xwiki-platform","forks_url":"https://api.github.com/repos/woshilapin/xwiki-platform/forks","keys_url":"https://api.github.com/repos/woshilapin/xwiki-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/woshilapin/xwiki-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/woshilapin/xwiki-platform/teams","hooks_url":"https://api.github.com/repos/woshilapin/xwiki-platform/hooks","issue_events_url":"https://api.github.com/repos/woshilapin/xwiki-platform/issues/events{/number}","events_url":"https://api.github.com/repos/woshilapin/xwiki-platform/events","assignees_url":"https://api.github.com/repos/woshilapin/xwiki-platform/assignees{/user}","branches_url":"https://api.github.com/repos/woshilapin/xwiki-platform/branches{/branch}","tags_url":"https://api.github.com/repos/woshilapin/xwiki-platform/tags","blobs_url":"https://api.github.com/repos/woshilapin/xwiki-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/woshilapin/xwiki-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/woshilapin/xwiki-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/woshilapin/xwiki-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/woshilapin/xwiki-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/woshilapin/xwiki-platform/languages","stargazers_url":"https://api.github.com/repos/woshilapin/xwiki-platform/stargazers","contributors_url":"https://api.github.com/repos/woshilapin/xwiki-platform/contributors","subscribers_url":"https://api.github.com/repos/woshilapin/xwiki-platform/subscribers","subscription_url":"https://api.github.com/repos/woshilapin/xwiki-platform/subscription","commits_url":"https://api.github.com/repos/woshilapin/xwiki-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/woshilapin/xwiki-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/woshilapin/xwiki-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/woshilapin/xwiki-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/woshilapin/xwiki-platform/contents/{+path}","compare_url":"https://api.github.com/repos/woshilapin/xwiki-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/woshilapin/xwiki-platform/merges","archive_url":"https://api.github.com/repos/woshilapin/xwiki-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/woshilapin/xwiki-platform/downloads","issues_url":"https://api.github.com/repos/woshilapin/xwiki-platform/issues{/number}","pulls_url":"https://api.github.com/repos/woshilapin/xwiki-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/woshilapin/xwiki-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/woshilapin/xwiki-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/woshilapin/xwiki-platform/labels{/name}","releases_url":"https://api.github.com/repos/woshilapin/xwiki-platform/releases{/id}","created_at":"2013-12-11T10:57:24Z","updated_at":"2015-03-31T14:46:09Z","pushed_at":"2015-04-01T08:39:56Z","git_url":"git://github.com/woshilapin/xwiki-platform.git","ssh_url":"git@github.com:woshilapin/xwiki-platform.git","clone_url":"https://github.com/woshilapin/xwiki-platform.git","svn_url":"https://github.com/woshilapin/xwiki-platform","homepage":"http://platform.xwiki.org/","size":264120,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"xwiki:master","ref":"master","sha":"27a39c497822b20223436aab0240ba18f26b4227","user":{"login":"xwiki","id":488445,"avatar_url":"https://avatars.githubusercontent.com/u/488445?v=3","gravatar_id":"","url":"https://api.github.com/users/xwiki","html_url":"https://github.com/xwiki","followers_url":"https://api.github.com/users/xwiki/followers","following_url":"https://api.github.com/users/xwiki/following{/other_user}","gists_url":"https://api.github.com/users/xwiki/gists{/gist_id}","starred_url":"https://api.github.com/users/xwiki/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xwiki/subscriptions","organizations_url":"https://api.github.com/users/xwiki/orgs","repos_url":"https://api.github.com/users/xwiki/repos","events_url":"https://api.github.com/users/xwiki/events{/privacy}","received_events_url":"https://api.github.com/users/xwiki/received_events","type":"Organization","site_admin":false},"repo":{"id":1463490,"name":"xwiki-platform","full_name":"xwiki/xwiki-platform","owner":{"login":"xwiki","id":488445,"avatar_url":"https://avatars.githubusercontent.com/u/488445?v=3","gravatar_id":"","url":"https://api.github.com/users/xwiki","html_url":"https://github.com/xwiki","followers_url":"https://api.github.com/users/xwiki/followers","following_url":"https://api.github.com/users/xwiki/following{/other_user}","gists_url":"https://api.github.com/users/xwiki/gists{/gist_id}","starred_url":"https://api.github.com/users/xwiki/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xwiki/subscriptions","organizations_url":"https://api.github.com/users/xwiki/orgs","repos_url":"https://api.github.com/users/xwiki/repos","events_url":"https://api.github.com/users/xwiki/events{/privacy}","received_events_url":"https://api.github.com/users/xwiki/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/xwiki/xwiki-platform","description":"The XWiki platform","fork":false,"url":"https://api.github.com/repos/xwiki/xwiki-platform","forks_url":"https://api.github.com/repos/xwiki/xwiki-platform/forks","keys_url":"https://api.github.com/repos/xwiki/xwiki-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/xwiki/xwiki-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/xwiki/xwiki-platform/teams","hooks_url":"https://api.github.com/repos/xwiki/xwiki-platform/hooks","issue_events_url":"https://api.github.com/repos/xwiki/xwiki-platform/issues/events{/number}","events_url":"https://api.github.com/repos/xwiki/xwiki-platform/events","assignees_url":"https://api.github.com/repos/xwiki/xwiki-platform/assignees{/user}","branches_url":"https://api.github.com/repos/xwiki/xwiki-platform/branches{/branch}","tags_url":"https://api.github.com/repos/xwiki/xwiki-platform/tags","blobs_url":"https://api.github.com/repos/xwiki/xwiki-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/xwiki/xwiki-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/xwiki/xwiki-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/xwiki/xwiki-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/xwiki/xwiki-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/xwiki/xwiki-platform/languages","stargazers_url":"https://api.github.com/repos/xwiki/xwiki-platform/stargazers","contributors_url":"https://api.github.com/repos/xwiki/xwiki-platform/contributors","subscribers_url":"https://api.github.com/repos/xwiki/xwiki-platform/subscribers","subscription_url":"https://api.github.com/repos/xwiki/xwiki-platform/subscription","commits_url":"https://api.github.com/repos/xwiki/xwiki-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/xwiki/xwiki-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/xwiki/xwiki-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/xwiki/xwiki-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/xwiki/xwiki-platform/contents/{+path}","compare_url":"https://api.github.com/repos/xwiki/xwiki-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/xwiki/xwiki-platform/merges","archive_url":"https://api.github.com/repos/xwiki/xwiki-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/xwiki/xwiki-platform/downloads","issues_url":"https://api.github.com/repos/xwiki/xwiki-platform/issues{/number}","pulls_url":"https://api.github.com/repos/xwiki/xwiki-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/xwiki/xwiki-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/xwiki/xwiki-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/xwiki/xwiki-platform/labels{/name}","releases_url":"https://api.github.com/repos/xwiki/xwiki-platform/releases{/id}","created_at":"2011-03-10T13:26:41Z","updated_at":"2015-04-01T11:56:56Z","pushed_at":"2015-04-01T11:56:56Z","git_url":"git://github.com/xwiki/xwiki-platform.git","ssh_url":"git@github.com:xwiki/xwiki-platform.git","clone_url":"https://github.com/xwiki/xwiki-platform.git","svn_url":"https://github.com/xwiki/xwiki-platform","homepage":"http://platform.xwiki.org/","size":661186,"stargazers_count":110,"watchers_count":110,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":138,"mirror_url":null,"open_issues_count":23,"forks":138,"open_issues":23,"watchers":110,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271"},"html":{"href":"https://github.com/xwiki/xwiki-platform/pull/271"},"issue":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/issues/271"},"comments":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/issues/271/comments"},"review_comments":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271/comments"},"review_comment":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/pulls/271/commits"},"statuses":{"href":"https://api.github.com/repos/xwiki/xwiki-platform/statuses/a543ab64794cec8c031f457767baf715e59e299f"}}}}