-
Notifications
You must be signed in to change notification settings - Fork 100
In unmarshaller, make errorLimitCounter customizable. #1154
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.sun.xml.bind.v2.runtime.unmarshaller; | ||
|
||
public class UnmarshallerProperties { | ||
public static final String ENABLE_ERROR_REPORT_LIMIT = "unmarshaller.enableErrorReportLimit"; | ||
public static final String ERROR_REPORT_LIMIT = "unmarshaller.errorReportLimit"; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,7 +68,6 @@ | |
import com.sun.istack.Nullable; | ||
import com.sun.istack.SAXParseException2; | ||
import com.sun.xml.bind.IDResolver; | ||
import com.sun.xml.bind.Util; | ||
import com.sun.xml.bind.api.AccessorException; | ||
import com.sun.xml.bind.api.ClassResolver; | ||
import com.sun.xml.bind.unmarshaller.InfosetScanner; | ||
|
@@ -77,8 +76,6 @@ | |
import com.sun.xml.bind.v2.runtime.Coordinator; | ||
import com.sun.xml.bind.v2.runtime.JAXBContextImpl; | ||
import com.sun.xml.bind.v2.runtime.JaxBeanInfo; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
import org.xml.sax.ErrorHandler; | ||
import org.xml.sax.Locator; | ||
|
@@ -199,13 +196,24 @@ public final class UnmarshallingContext extends Coordinator | |
*/ | ||
public @Nullable ClassLoader classLoader; | ||
|
||
public static volatile int DEFAULT_ERROR_COUNTER = 10; | ||
|
||
/** | ||
* The variable introduced to avoid reporting n^10 similar errors. | ||
* After error is reported counter is decremented. When it became 0 - errors should not be reported any more. | ||
* The variable introduced to avoid reporting more than {@value DEFAULT_ERROR_COUNTER} errors. | ||
* The default value can be overrode setting the {@link UnmarshallerProperties#ERROR_REPORT_LIMIT} property in the {@link Unmarshaller}. | ||
* After error is reported counter is decremented. When it became lower than 0, errors should not be reported any more. | ||
* If the {@link UnmarshallingContext#limitErrorReporting} is set to false, this field will be totally ignored. | ||
* | ||
* volatile is required to ensure that concurrent threads will see changed value | ||
*/ | ||
private static volatile int errorsCounter = 10; | ||
private volatile int errorsCounter = DEFAULT_ERROR_COUNTER; | ||
|
||
/** | ||
* Indicates if it should exist an error reporting limit. Default value is true. | ||
* This property can be overrode setting the setting the {@link UnmarshallerProperties#ENABLE_ERROR_REPORT_LIMIT} property in the {@link Unmarshaller}. | ||
* | ||
*/ | ||
private volatile boolean limitErrorReporting = true; | ||
|
||
/** | ||
* State information for each element. | ||
|
@@ -1336,28 +1344,36 @@ public StructureLoader getStructureLoader() { | |
return null; | ||
} | ||
|
||
public void setErrorsCounter(int errorsCounter) { | ||
this.errorsCounter = errorsCounter; | ||
} | ||
|
||
public void setLimitErrorReporting(boolean limitErrorReporting) { | ||
this.limitErrorReporting = limitErrorReporting; | ||
} | ||
|
||
/** | ||
* Based on current {@link Logger} {@link Level} and errorCounter value determines if error should be reported. | ||
* Based on current {@link UnmarshallingContext#limitErrorReporting} and errorCounter value determines if error should be reported. | ||
* | ||
* If the method called and return true it is expected that error will be reported. And that's why | ||
* errorCounter is automatically decremented during the check. | ||
* | ||
* NOT THREAD SAFE!!! In case of heave concurrency access several additional errors could be reported. It's not expected to be the | ||
* problem. Otherwise add synchronization here. | ||
* | ||
* @return true in case if {@link Level#FINEST} is set OR we haven't exceed errors reporting limit. | ||
* @return true in case if {@link UnmarshallingContext#limitErrorReporting} OR we haven't exceed errors reporting limit. | ||
*/ | ||
public boolean shouldErrorBeReported() throws SAXException { | ||
if (logger.isLoggable(Level.FINEST)) | ||
if (!limitErrorReporting) | ||
return true; | ||
|
||
if (errorsCounter >= 0) { | ||
--errorsCounter; | ||
if (errorsCounter == 0) // it's possible to miss this because of concurrency. If required add synchronization here | ||
if (errorsCounter == -1) // it's possible to miss this because of concurrency. If required add synchronization here | ||
handleEvent(new ValidationEventImpl(ValidationEvent.WARNING, Messages.ERRORS_LIMIT_EXCEEDED.format(), | ||
getLocator().getLocation(), null), true); | ||
} | ||
return errorsCounter >= 0; | ||
return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't work, if we always return false on shouldErrorBeReported(), error will never appear in the log. |
||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.sun.xml.bind.utils; | ||
|
||
import javax.xml.bind.annotation.XmlRootElement; | ||
|
||
@XmlRootElement | ||
public class Person { | ||
|
||
private String value; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package com.sun.xml.bind.v2.runtime.unmarshaller; | ||
|
||
import static com.sun.xml.bind.v2.runtime.unmarshaller.Messages.ERRORS_LIMIT_EXCEEDED; | ||
import static com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerProperties.ENABLE_ERROR_REPORT_LIMIT; | ||
import static com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.DEFAULT_ERROR_COUNTER; | ||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.junit.Assert.assertThat; | ||
|
||
import com.sun.xml.bind.utils.Person; | ||
|
||
import java.io.ByteArrayInputStream; | ||
|
||
import javax.xml.bind.JAXBContext; | ||
import javax.xml.bind.JAXBException; | ||
import javax.xml.bind.Unmarshaller; | ||
import javax.xml.bind.ValidationEvent; | ||
import javax.xml.bind.util.ValidationEventCollector; | ||
|
||
import junit.framework.TestCase; | ||
|
||
|
||
public class LimitErrorTest extends TestCase { | ||
|
||
private static final String EXPECTED_ERROR_MESSAGE = "unexpected element (uri:\"\", local:\"unexpectedChild\"). Expected elements are (none)"; | ||
private static final String GENERIC_ERROR_MESSAGE = ERRORS_LIMIT_EXCEEDED.format(); | ||
private final ValidationEventCollector validationCollector = new JAXB2ValidationEventCollector(); | ||
private static final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + | ||
"<person>" + | ||
"<unexpectedChild></unexpectedChild>" + | ||
"</person>"; | ||
|
||
private Unmarshaller unmarshaller = null; | ||
|
||
protected void setUp() throws Exception { | ||
unmarshaller = JAXBContext.newInstance(Person.class).createUnmarshaller(); | ||
unmarshaller.setEventHandler(validationCollector); | ||
} | ||
|
||
public void testDisableErrorReportLimit() throws Exception | ||
{ | ||
unmarshaller.setProperty(ENABLE_ERROR_REPORT_LIMIT, false); | ||
|
||
for (int i = 0; i < DEFAULT_ERROR_COUNTER + 1; i ++) { | ||
try { | ||
unmarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes())); | ||
} | ||
catch (JAXBException e) { | ||
assertThat(e.getMessage(), is(EXPECTED_ERROR_MESSAGE)); | ||
} | ||
} | ||
} | ||
|
||
public void testEnableErrorReportLimit() { | ||
|
||
for (int i = 0; i < DEFAULT_ERROR_COUNTER; i ++) { | ||
try { | ||
unmarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes())); | ||
} | ||
catch (JAXBException e) { | ||
assertThat(e.getMessage(), is(EXPECTED_ERROR_MESSAGE)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Due to |
||
} | ||
} | ||
|
||
try { | ||
unmarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes())); | ||
} | ||
catch (JAXBException e) { | ||
assertThat(e.getMessage(), is(GENERIC_ERROR_MESSAGE)); | ||
} | ||
} | ||
|
||
public void testCustomErrorReportLimit() { | ||
int customErrorReportLimit = 5; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. custom error limit is never passed to context here, so test will fail after fixing |
||
for (int i = 0; i < customErrorReportLimit; i ++) { | ||
try { | ||
unmarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes())); | ||
} | ||
catch (JAXBException e) { | ||
assertThat(e.getMessage(), is(EXPECTED_ERROR_MESSAGE)); | ||
} | ||
} | ||
|
||
try { | ||
unmarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes())); | ||
} | ||
catch (JAXBException e) { | ||
assertThat(e.getMessage(), is(GENERIC_ERROR_MESSAGE)); | ||
} | ||
} | ||
|
||
|
||
private class JAXB2ValidationEventCollector extends ValidationEventCollector { | ||
@Override | ||
public boolean handleEvent(ValidationEvent event) { | ||
super.handleEvent(event); | ||
return false; | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to comment on concurrency should be
errorsCounter < 0
instead of ==