docs: @Override
  	public T readFrom(CodedInputStream input) throws IOException {
  		T t;
  		try {
  			t = cls.newInstance();
  		} catch (InstantiationException e1) {
  			throw new IOException(e1.getMessage(), e1);
  		} catch (IllegalAccessException e1) {
  			throw new IOException(e1.getMessage(), e1);
  		}
  		try {
  			boolean done = false;
  			while (!done) {
  				int tag = input.readTag();
  				if (tag == 0) {
  					break;
  				}
  
  				FieldInfo fieldInfo = orderFieldsMapping.get(tag);
  				if (fieldInfo == null) {
  					input.skipField(tag);
  					// maybe new field added should be ignore
  					continue;
  				}
  				
  				// check list type
  				Field field = fieldInfo.getField();
  				Class<?> c = fieldInfo.getField().getType();
  				if (List.class.isAssignableFrom(c)) {
  					List list = (List) FieldUtils.getField(t, field);
  					if (list == null) {
  						list = new ArrayList();
  						FieldUtils.setField(t, field, list);
  					}
  					list.add(readValue(input, fieldInfo));
  					continue;
  				}
  
  				FieldType fieldType = fieldInfo.getFieldType();
  				switch (fieldType) {
  				case DOUBLE:
  					FieldUtils.setField(t, field, input.readDouble());
  					break;
  				case BYTES:
  					FieldUtils.setField(t, field, input.readBytes().toByteArray());
  					break;
  				case STRING:
  					FieldUtils.setField(t, field, input.readString());
  					break;
  				case BOOL:
  					FieldUtils.setField(t, field, input.readBool());
  					break;
  				case FIXED32:
  					FieldUtils.setField(t, field, input.readFixed32());
  					break;
  				case SFIXED32:
  					FieldUtils.setField(t, field, input.readSFixed32());
  					break;
  				case SINT32:
  					FieldUtils.setField(t, field, input.readSInt32());
  					break;
  				case INT32:
  					FieldUtils.setField(t, field, input.readInt32());
  					break;
  				case UINT32:
  					FieldUtils.setField(t, field, input.readUInt32());
  					break;
  				case FIXED64:
  					FieldUtils.setField(t, field, input.readFixed64());
  					break;
  				case SFIXED64:
  					FieldUtils.setField(t, field, input.readSFixed64());
  					break;
  				case SINT64:
  					FieldUtils.setField(t, field, input.readSInt64());
  					break;
  				case INT64:
  					FieldUtils.setField(t, field, input.readInt64());
  					break;
  				case UINT64:
  					FieldUtils.setField(t, field, input.readUInt64());
  					break;
  				case ENUM:
  					Class<?> type = field.getType();
  					try {
  						Method method = type.getMethod("values");
  						Enum[] inter = (Enum[]) method.invoke(null, null);
  
  						if (Enum.class.isAssignableFrom(type)) {
  							Enum value = CodedConstant.getEnum(inter, input.readEnum());
  							FieldUtils.setField(t, fieldInfo.getField(), value);
  						}
  					} catch (Exception e) {
  						throw new IOException(e.getMessage(), e);
  					}
  					break;
  				case FLOAT:
  					FieldUtils.setField(t, field, input.readFloat());
  					break;
  				case OBJECT:
  					ReflectiveCodec codec = new ReflectiveCodec(c);
  
  					int length = input.readRawVarint32();
  					final int oldLimit = input.pushLimit(length);
  					Object o = codec.readFrom(input);
  					FieldUtils.setField(t, fieldInfo.getField(), o);
  					break;
  				default:
  					throw new IOException("Unknown field type on field '" + fieldInfo.getField().getName() + "'");
  				}
  
  			}
  
  		} catch (com.google.protobuf.InvalidProtocolBufferException e) {
  			throw e;
  		} catch (java.io.IOException e) {
  			throw e;
  		}
  
  		return t;
  	}