001/* 002 * (C) Copyright 2015-2019 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nicolas Chapurlat <nchapurlat@nuxeo.com> 018 */ 019 020package org.nuxeo.ecm.core.io.marshallers.json.validation; 021 022import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON; 023import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE; 024 025import java.io.IOException; 026 027import org.nuxeo.ecm.core.api.validation.ConstraintViolation; 028import org.nuxeo.ecm.core.api.validation.ConstraintViolation.PathNode; 029import org.nuxeo.ecm.core.api.validation.DocumentValidationReport; 030import org.nuxeo.ecm.core.api.validation.ValidationViolation; 031import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter; 032import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher; 033import org.nuxeo.ecm.core.io.registry.reflect.Setup; 034import org.nuxeo.ecm.core.schema.types.constraints.Constraint; 035 036import com.fasterxml.jackson.core.JsonGenerator; 037 038/** 039 * Convert {@link DocumentValidationReport} to Json. 040 * <p> 041 * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing 042 * {@link DocumentValidationReport}. 043 * <p> 044 * This marshaller is also extensible: extend it and simply override 045 * {@link ExtensibleEntityJsonWriter#extend(Object, JsonGenerator)}. 046 * <p> 047 * Format is: 048 * 049 * <pre> 050 * { 051 * "entity-type":"validation_report", 052 * "has_error": true|false, 053 * "number": 123, <- number of errors present in this report 054 * "violations": [ 055 * { 056 * "message": "TheErrorMessage", 057 * "invalid_value": null|"THE_INVALID_VALUE_AS_STRING", 058 * "constraint": { 059 * see {@link ConstraintJsonWriter} format 060 * } 061 * }, 062 * ... 063 * ] 064 * <-- contextParameters if there are enrichers activated 065 * <-- additional property provided by extend() method 066 * } 067 * </pre> 068 * 069 * @since 7.2 070 */ 071@Setup(mode = SINGLETON, priority = REFERENCE) 072public class DocumentValidationReportJsonWriter extends ExtensibleEntityJsonWriter<DocumentValidationReport> { 073 074 public static final String ENTITY_TYPE = "validation_report"; 075 076 public DocumentValidationReportJsonWriter() { 077 super(ENTITY_TYPE, DocumentValidationReport.class); 078 } 079 080 @Override 081 protected void writeEntityBody(DocumentValidationReport report, JsonGenerator jg) throws IOException { 082 jg.writeBooleanField("has_error", report.hasError()); 083 jg.writeNumberField("number", report.numberOfErrors()); 084 // constraint violations 085 jg.writeArrayFieldStart("violations"); 086 for (ValidationViolation violation : report.asList()) { 087 jg.writeStartObject(); 088 String messageKey = violation.getMessageKey(); 089 jg.writeStringField("messageKey", messageKey); 090 // invalid value 091 if (violation instanceof ConstraintViolation) { 092 ConstraintViolation cv = (ConstraintViolation) violation; 093 // violation message 094 String message = cv.getMessage(ctx.getLocale()); 095 jg.writeStringField("message", message); 096 Object invalidValue = cv.getInvalidValue(); 097 if (invalidValue == null) { 098 jg.writeNullField("invalid_value"); 099 } else { 100 jg.writeStringField("invalid_value", invalidValue.toString()); 101 } 102 // violated constraint 103 Constraint constraint = cv.getConstraint(); 104 writeEntityField("constraint", constraint, jg); 105 // violation place 106 jg.writeArrayFieldStart("path"); 107 for (PathNode node : cv.getPath()) { 108 jg.writeStartObject(); 109 jg.writeStringField("field_name", node.getField().getName().getPrefixedName()); 110 jg.writeBooleanField("is_list_item", node.isListItem()); 111 if (node.isListItem()) { 112 jg.writeNumberField("index", node.getIndex()); 113 } 114 jg.writeEndObject(); 115 } 116 jg.writeEndArray(); 117 } 118 jg.writeEndObject(); 119 } 120 jg.writeEndArray(); 121 } 122 123}