diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/annotations/ProtocolBufferBased.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/annotations/ProtocolBufferBased.java new file mode 100644 index 0000000..4ee4b0c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/annotations/ProtocolBufferBased.java @@ -0,0 +1,17 @@ +package org.apache.hadoop.yarn.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.hadoop.classification.InterfaceStability; + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@InterfaceStability.Evolving +public @interface ProtocolBufferBased { + public Class pbClass(); +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/AllocateRequest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/AllocateRequest.java index 62316a6..4332478 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/AllocateRequest.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/AllocateRequest.java @@ -22,12 +22,14 @@ import org.apache.hadoop.classification.InterfaceAudience.Public; import org.apache.hadoop.classification.InterfaceStability.Stable; +import org.apache.hadoop.yarn.annotations.ProtocolBufferBased; import org.apache.hadoop.yarn.api.ApplicationMasterProtocol; import org.apache.hadoop.yarn.api.records.Container; import org.apache.hadoop.yarn.api.records.ContainerId; -import org.apache.hadoop.yarn.api.records.ResourceBlacklistRequest; import org.apache.hadoop.yarn.api.records.ContainerResourceIncreaseRequest; +import org.apache.hadoop.yarn.api.records.ResourceBlacklistRequest; import org.apache.hadoop.yarn.api.records.ResourceRequest; +import org.apache.hadoop.yarn.proto.YarnServiceProtos.AllocateRequestProto; import org.apache.hadoop.yarn.util.Records; /** @@ -53,7 +55,15 @@ */ @Public @Stable -public abstract class AllocateRequest { +@ProtocolBufferBased(pbClass = AllocateRequestProto.class) +public class AllocateRequest { + int responseId = Integer.MIN_VALUE; + float progress = Float.MIN_VALUE; + + List asks = null; + List releases = null; + ResourceBlacklistRequest blackList = null; + List increaseRequests = null; @Public @Stable @@ -88,7 +98,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract int getResponseId(); + public int getResponseId() { + return responseId; + } /** * Set the response id used to track duplicate responses. @@ -96,7 +108,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract void setResponseId(int id); + public void setResponseId(int id) { + this.responseId = id; + } /** * Get the current progress of application. @@ -104,7 +118,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract float getProgress(); + public float getProgress() { + return progress; + } /** * Set the current progress of application @@ -112,7 +128,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract void setProgress(float progress); + public void setProgress(float progress) { + this.progress = progress; + } /** * Get the list of ResourceRequest to update the @@ -122,7 +140,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract List getAskList(); + public List getAskList() { + return asks; + } /** * Set list of ResourceRequest to update the @@ -134,7 +154,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract void setAskList(List resourceRequests); + public void setAskList(List resourceRequests) { + this.asks = resourceRequests; + } /** * Get the list of ContainerId of containers being @@ -144,7 +166,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract List getReleaseList(); + public List getReleaseList() { + return releases; + } /** * Set the list of ContainerId of containers being @@ -155,7 +179,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract void setReleaseList(List releaseContainers); + public void setReleaseList(List releaseContainers) { + this.releases = releaseContainers; + } /** * Get the ResourceBlacklistRequest being sent by the @@ -166,7 +192,9 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract ResourceBlacklistRequest getResourceBlacklistRequest(); + public ResourceBlacklistRequest getResourceBlacklistRequest() { + return blackList; + } /** * Set the ResourceBlacklistRequest to inform the @@ -181,8 +209,10 @@ public static AllocateRequest newInstance(int responseID, float appProgress, */ @Public @Stable - public abstract void setResourceBlacklistRequest( - ResourceBlacklistRequest resourceBlacklistRequest); + public void setResourceBlacklistRequest( + ResourceBlacklistRequest resourceBlacklistRequest) { + this.blackList = resourceBlacklistRequest; + } /** * Get the ContainerResourceIncreaseRequest being sent by the @@ -190,7 +220,9 @@ public abstract void setResourceBlacklistRequest( */ @Public @Stable - public abstract List getIncreaseRequests(); + public List getIncreaseRequests() { + return increaseRequests; + } /** * Set the ContainerResourceIncreaseRequest to inform the @@ -199,6 +231,8 @@ public abstract void setResourceBlacklistRequest( */ @Public @Stable - public abstract void setIncreaseRequests( - List increaseRequests); + public void setIncreaseRequests( + List increaseRequests) { + this.increaseRequests = increaseRequests; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/PBTypeUnmatchException.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/PBTypeUnmatchException.java new file mode 100644 index 0000000..d385f1d --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/exceptions/PBTypeUnmatchException.java @@ -0,0 +1,17 @@ +package org.apache.hadoop.yarn.exceptions; + +public class PBTypeUnmatchException extends YarnException { + private static final long serialVersionUID = 4404654893667892853L; + + public PBTypeUnmatchException(Throwable cause) { + super(cause); + } + + public PBTypeUnmatchException(String message) { + super(message); + } + + public PBTypeUnmatchException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ApplicationMasterProtocolPBClientImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ApplicationMasterProtocolPBClientImpl.java index b64374f..a3f6476 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ApplicationMasterProtocolPBClientImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/impl/pb/client/ApplicationMasterProtocolPBClientImpl.java @@ -40,6 +40,7 @@ import org.apache.hadoop.yarn.api.protocolrecords.impl.pb.FinishApplicationMasterResponsePBImpl; import org.apache.hadoop.yarn.api.protocolrecords.impl.pb.RegisterApplicationMasterRequestPBImpl; import org.apache.hadoop.yarn.api.protocolrecords.impl.pb.RegisterApplicationMasterResponsePBImpl; +import org.apache.hadoop.yarn.api.records.impl.pb.ProtoSerdeUtils; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.ipc.RPCUtil; import org.apache.hadoop.yarn.proto.YarnServiceProtos.AllocateRequestProto; @@ -69,12 +70,13 @@ public void close() { } @Override - public AllocateResponse allocate(AllocateRequest request) - throws YarnException, IOException { + public AllocateResponse allocate(AllocateRequest request) throws YarnException, + IOException { AllocateRequestProto requestProto = - ((AllocateRequestPBImpl) request).getProto(); + (AllocateRequestProto) ProtoSerdeUtils.getProto(request, null); try { - return new AllocateResponsePBImpl(proxy.allocate(null, requestProto)); + return (AllocateResponse) ProtoSerdeUtils.getRecord( + proxy.allocate(null, requestProto), AllocateResponse.class); } catch (ServiceException e) { RPCUtil.unwrapAndThrowException(e); return null; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/AllocateRequestPBImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/AllocateRequestPBImpl.java deleted file mode 100644 index dc11165..0000000 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/protocolrecords/impl/pb/AllocateRequestPBImpl.java +++ /dev/null @@ -1,395 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.hadoop.yarn.api.protocolrecords.impl.pb; - - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.apache.hadoop.classification.InterfaceAudience.Private; -import org.apache.hadoop.classification.InterfaceStability.Unstable; -import org.apache.hadoop.yarn.api.protocolrecords.AllocateRequest; -import org.apache.hadoop.yarn.api.records.ContainerId; -import org.apache.hadoop.yarn.api.records.ContainerResourceIncreaseRequest; -import org.apache.hadoop.yarn.api.records.ResourceBlacklistRequest; -import org.apache.hadoop.yarn.api.records.ResourceRequest; -import org.apache.hadoop.yarn.api.records.impl.pb.ContainerIdPBImpl; -import org.apache.hadoop.yarn.api.records.impl.pb.ContainerResourceIncreaseRequestPBImpl; -import org.apache.hadoop.yarn.api.records.impl.pb.ResourceBlacklistRequestPBImpl; -import org.apache.hadoop.yarn.api.records.impl.pb.ResourceRequestPBImpl; -import org.apache.hadoop.yarn.proto.YarnProtos.ContainerIdProto; -import org.apache.hadoop.yarn.proto.YarnProtos.ContainerResourceIncreaseRequestProto; -import org.apache.hadoop.yarn.proto.YarnProtos.ResourceBlacklistRequestProto; -import org.apache.hadoop.yarn.proto.YarnProtos.ResourceRequestProto; -import org.apache.hadoop.yarn.proto.YarnServiceProtos.AllocateRequestProto; -import org.apache.hadoop.yarn.proto.YarnServiceProtos.AllocateRequestProtoOrBuilder; - -import com.google.protobuf.TextFormat; - -@Private -@Unstable -public class AllocateRequestPBImpl extends AllocateRequest { - AllocateRequestProto proto = AllocateRequestProto.getDefaultInstance(); - AllocateRequestProto.Builder builder = null; - boolean viaProto = false; - - private List ask = null; - private List release = null; - private List increaseRequests = null; - private ResourceBlacklistRequest blacklistRequest = null; - - public AllocateRequestPBImpl() { - builder = AllocateRequestProto.newBuilder(); - } - - public AllocateRequestPBImpl(AllocateRequestProto proto) { - this.proto = proto; - viaProto = true; - } - - public AllocateRequestProto getProto() { - mergeLocalToProto(); - proto = viaProto ? proto : builder.build(); - viaProto = true; - return proto; - } - - @Override - public int hashCode() { - return getProto().hashCode(); - } - - @Override - public boolean equals(Object other) { - if (other == null) - return false; - if (other.getClass().isAssignableFrom(this.getClass())) { - return this.getProto().equals(this.getClass().cast(other).getProto()); - } - return false; - } - - @Override - public String toString() { - return TextFormat.shortDebugString(getProto()); - } - - private void mergeLocalToBuilder() { - if (this.ask != null) { - addAsksToProto(); - } - if (this.release != null) { - addReleasesToProto(); - } - if (this.increaseRequests != null) { - addIncreaseRequestsToProto(); - } - if (this.blacklistRequest != null) { - builder.setBlacklistRequest(convertToProtoFormat(this.blacklistRequest)); - } - } - - private void mergeLocalToProto() { - if (viaProto) - maybeInitBuilder(); - mergeLocalToBuilder(); - proto = builder.build(); - viaProto = true; - } - - private void maybeInitBuilder() { - if (viaProto || builder == null) { - builder = AllocateRequestProto.newBuilder(proto); - } - viaProto = false; - } - - @Override - public int getResponseId() { - AllocateRequestProtoOrBuilder p = viaProto ? proto : builder; - return p.getResponseId(); - } - - @Override - public void setResponseId(int id) { - maybeInitBuilder(); - builder.setResponseId(id); - } - - @Override - public float getProgress() { - AllocateRequestProtoOrBuilder p = viaProto ? proto : builder; - return p.getProgress(); - } - - @Override - public void setProgress(float progress) { - maybeInitBuilder(); - builder.setProgress(progress); - } - - @Override - public List getAskList() { - initAsks(); - return this.ask; - } - - @Override - public void setAskList(final List resourceRequests) { - if(resourceRequests == null) { - return; - } - initAsks(); - this.ask.clear(); - this.ask.addAll(resourceRequests); - } - - @Override - public List getIncreaseRequests() { - initIncreaseRequests(); - return this.increaseRequests; - } - - @Override - public void setIncreaseRequests( - List increaseRequests) { - if (increaseRequests == null) { - return; - } - initIncreaseRequests(); - this.increaseRequests.clear(); - this.increaseRequests.addAll(increaseRequests); - } - - @Override - public ResourceBlacklistRequest getResourceBlacklistRequest() { - AllocateRequestProtoOrBuilder p = viaProto ? proto : builder; - if (this.blacklistRequest != null) { - return this.blacklistRequest; - } - if (!p.hasBlacklistRequest()) { - return null; - } - this.blacklistRequest = convertFromProtoFormat(p.getBlacklistRequest()); - return this.blacklistRequest; - } - - @Override - public void setResourceBlacklistRequest(ResourceBlacklistRequest blacklistRequest) { - maybeInitBuilder(); - if (blacklistRequest == null) { - builder.clearBlacklistRequest(); - } - this.blacklistRequest = blacklistRequest; - } - - private void initAsks() { - if (this.ask != null) { - return; - } - AllocateRequestProtoOrBuilder p = viaProto ? proto : builder; - List list = p.getAskList(); - this.ask = new ArrayList(); - - for (ResourceRequestProto c : list) { - this.ask.add(convertFromProtoFormat(c)); - } - } - - private void addAsksToProto() { - maybeInitBuilder(); - builder.clearAsk(); - if (ask == null) - return; - Iterable iterable = new Iterable() { - @Override - public Iterator iterator() { - return new Iterator() { - - Iterator iter = ask.iterator(); - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public ResourceRequestProto next() { - return convertToProtoFormat(iter.next()); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - - } - }; - - } - }; - builder.addAllAsk(iterable); - } - - private void initIncreaseRequests() { - if (this.increaseRequests != null) { - return; - } - AllocateRequestProtoOrBuilder p = viaProto ? proto : builder; - List list = - p.getIncreaseRequestList(); - this.increaseRequests = new ArrayList(); - - for (ContainerResourceIncreaseRequestProto c : list) { - this.increaseRequests.add(convertFromProtoFormat(c)); - } - } - - private void addIncreaseRequestsToProto() { - maybeInitBuilder(); - builder.clearIncreaseRequest(); - if (increaseRequests == null) { - return; - } - Iterable iterable = - new Iterable() { - @Override - public Iterator iterator() { - return new Iterator() { - - Iterator iter = - increaseRequests.iterator(); - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public ContainerResourceIncreaseRequestProto next() { - return convertToProtoFormat(iter.next()); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - - } - }; - builder.addAllIncreaseRequest(iterable); - } - - @Override - public List getReleaseList() { - initReleases(); - return this.release; - } - @Override - public void setReleaseList(List releaseContainers) { - if(releaseContainers == null) { - return; - } - initReleases(); - this.release.clear(); - this.release.addAll(releaseContainers); - } - - private void initReleases() { - if (this.release != null) { - return; - } - AllocateRequestProtoOrBuilder p = viaProto ? proto : builder; - List list = p.getReleaseList(); - this.release = new ArrayList(); - - for (ContainerIdProto c : list) { - this.release.add(convertFromProtoFormat(c)); - } - } - - private void addReleasesToProto() { - maybeInitBuilder(); - builder.clearRelease(); - if (release == null) - return; - Iterable iterable = new Iterable() { - @Override - public Iterator iterator() { - return new Iterator() { - - Iterator iter = release.iterator(); - - @Override - public boolean hasNext() { - return iter.hasNext(); - } - - @Override - public ContainerIdProto next() { - return convertToProtoFormat(iter.next()); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - - } - }; - - } - }; - builder.addAllRelease(iterable); - } - - private ResourceRequestPBImpl convertFromProtoFormat(ResourceRequestProto p) { - return new ResourceRequestPBImpl(p); - } - - private ResourceRequestProto convertToProtoFormat(ResourceRequest t) { - return ((ResourceRequestPBImpl)t).getProto(); - } - - private ContainerResourceIncreaseRequestPBImpl convertFromProtoFormat( - ContainerResourceIncreaseRequestProto p) { - return new ContainerResourceIncreaseRequestPBImpl(p); - } - - private ContainerResourceIncreaseRequestProto convertToProtoFormat( - ContainerResourceIncreaseRequest t) { - return ((ContainerResourceIncreaseRequestPBImpl) t).getProto(); - } - - private ContainerIdPBImpl convertFromProtoFormat(ContainerIdProto p) { - return new ContainerIdPBImpl(p); - } - - private ContainerIdProto convertToProtoFormat(ContainerId t) { - return ((ContainerIdPBImpl)t).getProto(); - } - - private ResourceBlacklistRequestPBImpl convertFromProtoFormat(ResourceBlacklistRequestProto p) { - return new ResourceBlacklistRequestPBImpl(p); - } - - private ResourceBlacklistRequestProto convertToProtoFormat(ResourceBlacklistRequest t) { - return ((ResourceBlacklistRequestPBImpl)t).getProto(); - } -} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ProtoSerdeUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ProtoSerdeUtils.java new file mode 100644 index 0000000..6680499 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/api/records/impl/pb/ProtoSerdeUtils.java @@ -0,0 +1,175 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.api.records.impl.pb; + +import java.lang.reflect.Method; +import java.util.Map; + +import org.apache.hadoop.yarn.annotations.ProtocolBufferBased; +import org.apache.hadoop.yarn.exceptions.PBTypeUnmatchException; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.GeneratedMessage; +import com.sun.xml.bind.v2.schemagen.xmlschema.List; + +public class ProtoSerdeUtils { + private static final String BUILDER_SUFFIX = ".Builder"; + + public static Object getRecord(Object proto, Class recordClass) { + return null; + } + + public static GeneratedMessage getProto(Object record, Class recordProtoClass) + throws PBTypeUnmatchException { + try { + Class builderCls; + if (null == recordProtoClass) { + builderCls = getBuilderClassByProtoClass(recordProtoClass); + } else { + builderCls = getBuilderClassByProtoClass(getProtoClass(record)); + } + + Object[] emptyObjArray = new Object[0]; + Class[] emptyClsArray = new Class[0]; + + // create a builder + Object builder = + builderCls.getMethod("newBuilder", emptyClsArray).invoke(null, + emptyObjArray); + + Descriptor descriptor = + (Descriptor) builderCls.getMethod("getDescriptorForType", emptyClsArray) + .invoke(builder, emptyObjArray); + + // go through all descriptors, and invoke corresponding getters + for (FieldDescriptor fd : descriptor.getFields()) { + String suffix = getMethodSuffix(fd.getName()); + + // get getter method + Method getterMethod = + record.getClass().getMethod("get" + suffix, emptyClsArray); + + // primitive types + Class returnType = getterMethod.getReturnType(); + if (Integer.TYPE == returnType) { + int v = (Integer) getterMethod.invoke(record, emptyObjArray); + // min_value means this not set by user yet + if (Integer.MIN_VALUE != v) { + builderCls.getMethod("set" + suffix, Integer.class).invoke(builder, + new Object[] { v }); + } + } else if (Long.TYPE == returnType) { + long v = (Long) getterMethod.invoke(record, emptyObjArray); + // min_value means this not set by user yet + if (Long.MIN_VALUE != v) { + builderCls.getMethod("set" + suffix, Long.class).invoke(builder, + new Object[] { v }); + } + } else if (Float.TYPE == returnType) { + float v = (Float) getterMethod.invoke(record, emptyObjArray); + // less than 1e-8 means this not set by user yet + if (Float.MIN_VALUE != v) { + builderCls.getMethod("set" + suffix, Float.class).invoke(builder, + new Object[] { v }); + } + } else if (Double.TYPE == returnType) { + // currently, we don't have "double" in proto file, add this only for + // consistency + double v = (Double) getterMethod.invoke(record, emptyObjArray); + // min_value means this not set by user yet + if (Double.MIN_VALUE != v) { + builderCls.getMethod("set" + suffix, Double.class).invoke(builder, + new Object[] { v }); + } + } else if (String.class == returnType) { + String v = (String) getterMethod.invoke(record, emptyObjArray); + if (null != v) { + builderCls.getMethod("set" + suffix, String.class).invoke(builder, + new Object[] { v }); + } + } else if (returnType.isEnum()) { + // TODO + } else if (List.class == getterMethod.getReturnType()) { + // TODO + } else if (Map.class == getterMethod.getReturnType()) { + // TODO + } else { + // for other types, recursively transfer it to PB type + Object v = getterMethod.invoke(record, emptyObjArray); + if (null != v) { + Class protoCls = getProtoClass(v); + Object proto = getProto(v, protoCls); + builderCls.getMethod("set" + suffix, protoCls).invoke(builder, + new Object[] { proto }); + } + } + } + return (GeneratedMessage) builderCls.getMethod("build", emptyClsArray) + .invoke(builder, emptyObjArray); + } catch (ReflectiveOperationException e) { + throw new PBTypeUnmatchException(e); + } + } + + private static Class getProtoClass(Object record) + throws PBTypeUnmatchException { + // check if this obj marked PB based + ProtocolBufferBased annotation = + record.getClass().getAnnotation(ProtocolBufferBased.class); + if (null == annotation) { + throw new PBTypeUnmatchException( + String.format("class:%s not marked @%s", record.getClass() + .getCanonicalName(), ProtocolBufferBased.class.getName())); + } + if (null == annotation.pbClass()) { + throw new PBTypeUnmatchException(String.format( + "class:%s marked @%s, but pbClass not specified", record.getClass() + .getCanonicalName(), ProtocolBufferBased.class.getName())); + } + + // get proto class + Class protoClass; + try { + protoClass = Class.forName(annotation.getClass().getCanonicalName()); + } catch (ClassNotFoundException e) { + throw new PBTypeUnmatchException(e); + } + return protoClass; + } + + private static Class getBuilderClassByProtoClass(Class protoClass) + throws ClassNotFoundException { + // get builder class + Class builderCls; + builderCls = Class.forName(protoClass.getCanonicalName() + BUILDER_SUFFIX); + return builderCls; + } + + private static String getMethodSuffix(String fdName) { + StringBuilder builder = new StringBuilder(); + for (String part : fdName.split("_")) { + builder.append(Character.toUpperCase(part.charAt(0))); + for (int i = 1; i < part.length(); i++) { + builder.append(part.charAt(i)); + } + } + return builder.toString(); + } +}