/** * Set the default values for the non defined fields. * * @param model the model which has its default fields set. * @throws IllegalAccessException if the underlying fields are inaccessible * @throws Exception In case the field cannot be parsed */ private void setDefaultValuesForFields(final Map<String, Object> model) throws IllegalAccessException, Exception { // Set the default values, if defined for (int i = 1; i <= dataFields.size(); i++) { Field field = annotatedFields.get(i); field.setAccessible(true); DataField dataField = dataFields.get(i); Object modelField = model.get(field.getDeclaringClass().getName()); if (field.get(modelField) == null && !dataField.defaultValue().isEmpty()) { Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); Object value = format.parse(dataField.defaultValue()); field.set(modelField, value); } } }
public void bind(List<String> tokens, Map<String, Object> model, int line) throws Exception { int pos = 1; int counterMandatoryFields = 0; for (String data : tokens) { // Get DataField from model DataField dataField = dataFields.get(pos); ObjectHelper.notNull( dataField, "No position " + pos + " defined for the field: " + data + ", line: " + line); if (dataField.trim()) { data = data.trim(); } if (dataField.required()) { // Increment counter of mandatory fields ++counterMandatoryFields; // Check if content of the field is empty // This is not possible for mandatory fields if (data.equals("")) { throw new IllegalArgumentException( "The mandatory field defined at the position " + pos + " is empty for the line: " + line); } } // Get Field to be setted Field field = annotatedFields.get(pos); field.setAccessible(true); if (LOG.isDebugEnabled()) { LOG.debug("Pos: {}, Data: {}, Field type: {}", new Object[] {pos, data, field.getType()}); } // Create format object to format the field Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); // field object to be set Object modelField = model.get(field.getDeclaringClass().getName()); // format the data received Object value = null; if (!data.equals("")) { try { value = format.parse(data); } catch (FormatException ie) { throw new IllegalArgumentException( ie.getMessage() + ", position: " + pos + ", line: " + line, ie); } catch (Exception e) { throw new IllegalArgumentException( "Parsing error detected for field defined at the position: " + pos + ", line: " + line, e); } } else { if (!dataField.defaultValue().isEmpty()) { value = format.parse(dataField.defaultValue()); } else { value = getDefaultValueForPrimitive(field.getType()); } } field.set(modelField, value); ++pos; } LOG.debug("Counter mandatory fields: {}", counterMandatoryFields); if (counterMandatoryFields < numberMandatoryFields) { throw new IllegalArgumentException("Some mandatory fields are missing, line: " + line); } if (pos < totalFields) { setDefaultValuesForFields(model); } }
/** * Generate a table containing the data formatted and sorted with their position/offset If the * model is Ordered than a key is created combining the annotation @Section and Position of the * field If a relation @OneToMany is defined, than we iterate recursively through this function * The result is placed in the Map<Integer, List> results */ private void generateCsvPositionMap( Class<?> clazz, Object obj, Map<Integer, List<String>> results) throws Exception { String result = ""; for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); DataField datafield = field.getAnnotation(DataField.class); if (datafield != null) { if (obj != null) { // Retrieve the format, pattern and precision associated to the type Class<?> type = field.getType(); // Create format Format<?> format = FormatFactory.getFormat(type, getLocale(), datafield); // Get field value Object value = field.get(obj); result = formatString(format, value); if (datafield.trim()) { result = result.trim(); } if (datafield.clip() && result.length() > datafield.length()) { result = result.substring(0, datafield.length()); } if (LOG.isDebugEnabled()) { LOG.debug( "Value to be formatted: {}, position: {}, and its formatted value: {}", new Object[] {value, datafield.pos(), result}); } } else { result = ""; } Integer key; if (isMessageOrdered() && obj != null) { // Generate a key using the number of the section // and the position of the field Integer key1 = sections.get(obj.getClass().getName()); Integer key2 = datafield.position(); Integer keyGenerated = generateKey(key1, key2); if (LOG.isDebugEnabled()) { LOG.debug("Key generated: {}, for section: {}", String.valueOf(keyGenerated), key1); } key = keyGenerated; } else { key = datafield.pos(); } if (!results.containsKey(key)) { List<String> list = new LinkedList<String>(); list.add(result); results.put(key, list); } else { List<String> list = results.get(key); list.add(result); } } OneToMany oneToMany = field.getAnnotation(OneToMany.class); if (oneToMany != null) { // Set global variable // Will be used during generation of CSV isOneToMany = true; List<?> list = (List<?>) field.get(obj); if (list != null) { Iterator<?> it = list.iterator(); while (it.hasNext()) { Object target = it.next(); generateCsvPositionMap(target.getClass(), target, results); } } else { // Call this function to add empty value // in the table generateCsvPositionMap(field.getClass(), null, results); } } } }
/** * Unit test for {@link JsonJacksonFormat} * * @author [email protected] Jeffrey Damick */ public class JsonJacksonFormatTest { // since jackson doesn't append spaces after the colon... private static final String unknownFieldsText = TestUtil.readTextFromFile("json_format_unknown_fields_data.txt").replaceAll(": ", ":"); private static final String bogusJson = "{\"default_string\":\"!@##&*)&*(&*&*&*\"}{))_+__+$$(((((((((((((((()!?:\">\"}"; private static final String validJson = "{\"default_string\":\"!@##&*)&*(&*&*&*\\\"}{))_+__+$$(((((((((((((((()!?:\\\">\"}"; private FormatFactory formatFactory = new FormatFactory(); private ProtobufFormatter formatter = formatFactory.createFormatter(Formatter.JSON_JACKSON); @Before public void setup() { formatter.setDefaultCharset(Charset.forName("UTF-8")); } @Test public void testStackOverflow() throws Exception { TestAllTypes bd = TestAllTypes.newBuilder().setDefaultBytes(ByteString.copyFrom(new byte[1024])).build(); String jsonText = formatter.printToString(bd); TestAllTypes.Builder builder = TestAllTypes.newBuilder(); formatter.merge(TextUtils.toInputStream(jsonText), builder); } @Test public void testUnknown() throws Exception { TestAllTypes allTypes = TestAllTypes.newBuilder() .setDefaultInt32(123) .setOptionalInt64(456l) .setOptionalString("foo") .setOptionalImportMessage(ImportMessage.newBuilder().setD(123)) .build(); String javaText = formatter.printToString(allTypes); // System.out.println(javaText); assertEquals("json doesn't match", unknownFieldsText, javaText); TestAllTypes.Builder builder = TestAllTypes.newBuilder(); formatter.merge(TextUtils.toInputStream(javaText), builder); assertEquals(allTypes, builder.build()); } @Test public void testMoreUnknown() throws Exception { UnknownFieldSet unknownGroupLevel2 = UnknownFieldSet.newBuilder() .addField(16, UnknownFieldSet.Field.newBuilder().addVarint(566667).build()) .build(); UnknownFieldSet unknownGroup = UnknownFieldSet.newBuilder() .addField(11, UnknownFieldSet.Field.newBuilder().addVarint(566667).build()) .addField(15, UnknownFieldSet.Field.newBuilder().addGroup(unknownGroupLevel2).build()) .build(); ByteString bs = ByteString.copyFromUtf8("testUnknown"); OneString data = OneString.newBuilder() .setUnknownFields( UnknownFieldSet.newBuilder() .addField(5, UnknownFieldSet.Field.newBuilder().addFixed32(999).build()) .addField(6, UnknownFieldSet.Field.newBuilder().addGroup(unknownGroup).build()) .addField(7, UnknownFieldSet.Field.newBuilder().addLengthDelimited(bs).build()) .build()) .setData("12345") .build(); String javaText = formatter.printToString(data); // System.out.println(javaText); OneString.Builder builder = OneString.newBuilder(); formatter.merge(TextUtils.toInputStream(javaText), builder); assertEquals(data.getData(), builder.build().getData()); } @Test public void testInvalidJson() throws Exception { TestAllTypes msg = TestAllTypes.newBuilder() .setDefaultString("!@##&*)&*(&*&*&*\"}{))_+__+$$(((((((((((((((()!?:\">") .build(); String javaText = formatter.printToString(msg); // System.out.println(javaText); assertEquals(javaText, validJson); TestAllTypes.Builder builder = TestAllTypes.newBuilder(); try { formatter.merge(TextUtils.toInputStream(bogusJson), builder); fail("Expect parsing error due to malformed JSON"); } catch (Exception e) { // good } } @Test public void testStringValueContainsSurrogatePair() throws Exception { String testString = new String(Character.toChars(0x1D11E)); OneString msg = OneString.newBuilder().setData(testString).build(); String json = formatter.printToString(msg); // Assert that the surrogate pair was encoded assertEquals("{\"data\":\"\\uD834\\uDD1E\"}", json); // Assert that we can read the string back into a msg OneString.Builder builder = OneString.newBuilder(); formatter.merge(TextUtils.toInputStream(json), builder); assertEquals(msg, builder.build()); } @Test public void testStringValueContainsControlCharacters() throws Exception { char[] ctrlChars = new char[0x001F + 1]; for (char c = 0; c < 0x001F + 1; c++) { ctrlChars[c] = c; } String testString = new String(ctrlChars); OneString msg = OneString.newBuilder().setData(testString).build(); String json = formatter.printToString(msg); // Assert that we can read the string back into a msg OneString.Builder builder = OneString.newBuilder(); formatter.merge(TextUtils.toInputStream(json), builder); OneString item = builder.build(); assertEquals(msg, item); assertTrue(Arrays.equals(ctrlChars, item.getData().toCharArray())); } @Test public void testStringValueContainsCharactersThatShouldBeEscaped() throws Exception { // input string is \"' String testString = "\\\"'"; OneString msg = OneString.newBuilder().setData(testString).build(); String json = formatter.printToString(msg); // Assert that reverse-solidus and double quotes where escaped using a reverse-solidus // Expected string is {"name": "\\\"'"} assertEquals("{\"data\":\"\\\\\\\"\'\"}", json); // Assert that we can read the string back into a msg OneString.Builder builder = OneString.newBuilder(); formatter.merge(TextUtils.toInputStream(json), builder); assertEquals(msg, builder.build()); } @Test public void testNestedExtension() throws Exception { ExtensionRegistry registry = ExtensionRegistry.newInstance(); UnittestProto.registerAllExtensions(registry); UnittestProto.TestAllExtensions tae = UnittestProto.TestAllExtensions.newBuilder() .setExtension(TestNestedExtension.test, "aTest") .build(); String output = formatter.printToString(tae); UnittestProto.TestAllExtensions.Builder builder = UnittestProto.TestAllExtensions.newBuilder(); formatter.merge(TextUtils.toInputStream(output), registry, builder); String value = builder.build().getExtension(TestNestedExtension.test); assertEquals("aTest", value); } @Test public void testChineseCharacters() throws Exception { String data = "検索jan5検索[email protected]"; String testString = "{\"data\":\"" + data + "\"}"; OneString.Builder builder = OneString.newBuilder(); formatter.merge(TextUtils.toInputStream(testString, Charset.forName("UTF-8")), builder); OneString msg = builder.build(); // System.out.println(msg.getData()); assertEquals(data, msg.getData()); } }