pojo 에 대한 protobuf 의 직접 디 코딩 실현

protobuf 의 디 코딩 은 성능 이 높 고 전송 데이터 가 적 으 며 언어 간 의 특징 을 가지 고 있 습 니 다.프로 토 버 프 공식 문서 에 따 르 면
https://developers.google.com/protocol-buffers/docs/overview에서 말 한 것 은 먼저 protoc 컴 파일 러 로 대응 하 는 언어의 디 코딩 대 리 를 만 든 다음 에 프 록 시 build 와 parse 데 이 터 를 사용 해 야 합 니 다.
내 응용 장면 에서 스 크 립 트 를 사용 하여 설정 에 따라 자바 pojo 소스 코드 와 대응 하 는 proto 파일 을 직접 생 성하 고 pojo 에 자신의 디 코딩 방법 을 추가 합 니 다.이렇게 되면 protoc 를 호출 하여 프 록 시 를 만 드 는 전략 을 사용 하 는 것 이 매우 서 툴 러 보 입 니 다.또한 protobuf 가 프 록 시 클래스 로 인 코딩 데 이 터 를 풀 수 있 으 니 이론 적 으로 직접 인 코딩 데 이 터 를 만 드 는 것 도 가능 하지만 안 타 깝 게 도 구 글 은 이러한 문서 설명 을 제공 하지 않 았 습 니 다.
구 글 을 거 친 후,stackoverflow 에 서 는 Descriptor 가 proto 파일 을 묘사 하고,C++로 이 루어 진 직접 디 코딩 코드 도 있 습 니 다.자바 쪽 은 매우 적 습 니 다.한 친구 만 공유 할 수 있 습 니 다.
감사 드 립 니 다.
다음은 디 코딩 코드 의 실현 입 니 다.

package miniserver.util;

import static miniserver.util.ReflectionUtil.gatherAllFields;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.DynamicMessage.Builder;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;

public class ProtoParserOrBuilder {
	private Map<String, Descriptor> descriptors = null;
	private static final String TEMP_DIR = "D://";
	public static final String PROTOC_PATH = System.getProperty("user.dir")
			+ "/protoc/protoc.exe";
	private File descFile;

	public ProtoParserOrBuilder() {
		descriptors = new HashMap<String, Descriptor>();
	}

	public ProtoParserOrBuilder(File proto) {
		descriptors = new HashMap<String, Descriptor>();

		init(proto);
	}

	private void init(File proto) {
		if (descFile != null && descFile.exists()) {
			descFile.delete();
		}
		this.descFile = createDescripFile(proto);

		FileInputStream fin = null;
		try {
			fin = new FileInputStream(descFile);

			FileDescriptorSet descriptorSet = FileDescriptorSet.parseFrom(fin);

			for (FileDescriptorProto fdp : descriptorSet.getFileList()) {
				FileDescriptor fd = FileDescriptor.buildFrom(fdp,
						new FileDescriptor[] {});

				for (Descriptor descriptor : fd.getMessageTypes()) {
					String className = descriptor.getName();

					this.descriptors.put(className, descriptor);
				}
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (DescriptorValidationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				if (fin != null) {
					fin.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private File createDescripFile(File proto) {
		try {
			Runtime run = Runtime.getRuntime();
			String descFileName = System.currentTimeMillis()
					+ "FastProtoParser.desc";
			String protoPath = proto.getCanonicalPath();
			String protoFPath = proto.getParentFile().getAbsolutePath();

			String cmd = PROTOC_PATH + " -I=" + protoFPath
					+ " --descriptor_set_out=" + TEMP_DIR + descFileName + " "
					+ protoPath;
			System.out.println(cmd);

			//        ,    desc    
			Process p = run.exec(cmd);
			if (p.waitFor() != 0) {
				if (p.exitValue() == 1) {// p.exitValue()==0      ,1:     
					throw new RuntimeException("protoc      ");
				}
			}

			return new File(TEMP_DIR + descFileName);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;

	}

	public <T> T parse(Class<T> clazz, byte[] bytes) {
		String className = clazz.getSimpleName();
		Descriptor desc = this.descriptors.get(className);

		Map<String, String> fields = new HashMap<String, String>();
		try {
			DynamicMessage message = DynamicMessage.parseFrom(desc, bytes);
			Map<FieldDescriptor, Object> fieldDescs = message.getAllFields();
			for (Map.Entry<FieldDescriptor, Object> entry : fieldDescs
					.entrySet()) {
				fields.put(entry.getKey().getName(), entry.getValue()
						.toString());
			}

			T instance = clazz.newInstance();

			List<Field> fieldList = ReflectionUtil.gatherAllFields(clazz);
			for (Field f : fieldList) {
				ReflectionUtil.fillField(fields, instance, f);
			}

			return instance;
		} catch (InvalidProtocolBufferException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;

	}

	public byte[] build(Object obj) {

		Class<? extends Object> clazz = obj.getClass();
		String className = clazz.getSimpleName();

		Descriptor desc = this.descriptors.get(className);

		Builder builder = DynamicMessage.newBuilder(desc);
		List<FieldDescriptor> fieldDescs = desc.getFields();
		List<Field> fields = gatherAllFields(clazz);
		try {
			Map<String, Object> fieldValues = new HashMap<String, Object>();
			for (Field field : fields) {
				field.setAccessible(true);
				String fieldName = field.getName();
				Object fieldValueObject;
				fieldValueObject = field.get(obj);
				if (fieldValueObject != null) {
					fieldValues.put(fieldName, fieldValueObject);
				}
			}

			for (FieldDescriptor fieldDesc : fieldDescs) {
				String fieldName = fieldDesc.getName();
				Object val = fieldValues.get(fieldName);
				if (val != null) {
					builder.setField(fieldDesc, val);
				}
			}

			Message message = builder.build();

			return message.toByteArray();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();

		this.descFile.delete();
	}

}

이미 검증 을 거 쳤 습 니 다.프 록 시 클래스 에서 생 성 된 데이터 와 똑 같 고 해석 에 도 문제 가 없 으 니 안심 하고 사용 하 십시오.
본 보 의 오리지널 사 이 트 는 ITeye 입 니 다.다시 전재 가 있 으 면 출처 를 밝 혀 주 십시오.합작 해 주 셔 서 감사합니다.

좋은 웹페이지 즐겨찾기