根据要发送的数据构建数据报（编码采用当前系统默认编码）

@param body    要发送的数据
@param type    数据报类型（0：心跳包；1：内置MVC数据处理器数据类型；2：文件传输；3：ACK；4：后端主动发往前端的数据）
@param version 数据报版本
@return 构建好的数据报对象
@throws DataOutOfMemory 当数据长度过长时会抛出该异常
481373
public static Datagram build(final byte[] body, final byte type,
                                 final byte version) throws DataOutOfMemory {
        final int dataLen;
        if (body != null && body.length != 0) {
            // 获取要发送的数据的长度
            dataLen = body.length;
            log.info("要构建的数据报的body长度为：{}", dataLen);
        } else {
            dataLen = 0;
            log.info("要构建一个空的数据报");
        }

        if (log.isDebugEnabled()) {
            log.debug("要发送的数据为：{}", Arrays.toString(body));
        }
        if (dataLen > MAX_LENGTH) {
            // 数据报超出最大值
            log.error("数据报数据长度超过最大值：{}", MAX_LENGTH);
            throw new DataOutOfMemory(String.format("数据长度超过最大值%d", MAX_LENGTH));
        }

        try (PooledObject<ByteArray> holder = POOL.get()) {
            // 缓存
            ByteArray buffer = holder.get();
            // 一个字节的版本号
            buffer.append(version);
            // 四个字节的body长度
            buffer.append(convert(dataLen));
            // 一个字节的数据类型
            buffer.append(type);
            // 十个字节的字符集，字符集为当前系统默认字符集不可更改，不足十个字节的用0填充
            buffer.append(CHARSET_DATA);

            //添加ID字段
            byte[] idDatas = Tools.createUUID().getBytes();
            int idLen = idDatas.length;
            buffer.append(idDatas);
            //ID不足40byte的补0
            for (int i = idLen; i < 40; i++) {
                buffer.append((byte) 0);
            }

            if (dataLen != 0) {
                // 填充数据
                buffer.append(body);
            }

            Datagram datagram = new Datagram(buffer.getData(), dataLen, body, version, CHARSET,
                type, idDatas);
            if (log.isDebugEnabled()) {
                log.debug("转换后的数据报是：{}", datagram);
            }
            return datagram;
        }
    }
851119
protected AbstractMetadataResolver getMetadataResolverFromResponse(final HttpResponse response, final File backupFile) throws Exception {
        val entity = response.getEntity();
        val result = IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8);
        val path = backupFile.toPath();
        LOGGER.trace("Writing metadata to file at [{}]", path);
        try (val output = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
            IOUtils.write(result, output);
            output.flush();
        }
        EntityUtils.consume(entity);
        return new InMemoryResourceMetadataResolver(backupFile, configBean);
    }
229194
@SuppressWarnings("unchecked")
    public <T extends Number> T readBodyAsNumber(Class<T> type) {
        String messageContent = readBodyAndValidateForNumber();
        if (type.equals(BigDecimal.class)) {
            return (T)new BigDecimal(messageContent);
        } else if (type.equals(BigInteger.class)) {
            return (T)new BigInteger(messageContent);
        } else if (type.equals(Byte.class)) {
            return (T)Byte.valueOf(messageContent);
        } else if (type.equals(Short.class)) {
            return (T)Short.valueOf(messageContent);
        } else if (type.equals(Integer.class)) {
            return (T)Integer.valueOf(messageContent);
        } else if (type.equals(Long.class)) {
            return (T)Long.valueOf(messageContent);
        } else {
            throw new RuntimeException("Unsupported number format: " + type);
        }
    }
188471
@Override
	public List<RecordSessionUrl> getUrlsForType (int type) throws DatabaseException {
    	SqlPreparedStatementWrapper psGetAlluRLSForType = null;
        try {
        	psGetAlluRLSForType = DbSQL.getSingleton().getPreparedStatement("sessionurl.ps.geturlsfortype");
			psGetAlluRLSForType.getPs().setInt(1, type);
			try (ResultSet rs = psGetAlluRLSForType.getPs().executeQuery()) {
				List<RecordSessionUrl> result = new ArrayList<>();
				while (rs.next()) {
					result.add(new RecordSessionUrl(rs.getLong(URLID), rs.getInt(TYPE), rs.getString(URL)));
				}
				return result;
			}
		} catch (SQLException e) {
			throw new DatabaseException(e);
		} finally {
			DbSQL.getSingleton().releasePreparedStatement(psGetAlluRLSForType);
		}
    }
952676
@Override
	public byte[] getBody() {
		if (this.cachedBody == null || this.cachedBody.length == 0) {
			try {
				if (this.request instanceof MockHttpServletRequest) {
					this.cachedBody = ((MockHttpServletRequest) this.request)
							.getContentAsByteArray();
					return this.cachedBody;
				}
				byte[] body = toByteArray(this.request.getInputStream());
				boolean isGzipped = hasGzipEncoding() || Gzip.isGzipped(body);
				this.cachedBody = isGzipped ? Gzip.unGzip(body) : body;
			}
			catch (IOException ioe) {
				throw new RuntimeException(ioe);
			}
		}
		return this.cachedBody;
	}
687137
@PUT
    @Consumes(Servlets.JSON_MEDIA_TYPE)
    @Produces(Servlets.JSON_MEDIA_TYPE)
    @Path("/uniqueAttribute/type/{typeName}")
    public EntityMutationResponse partialUpdateEntityByUniqueAttrs(@PathParam("typeName") String typeName,
                                                                   @Context HttpServletRequest servletRequest,
                                                                   AtlasEntityWithExtInfo entityInfo) throws Exception {
        AtlasPerfTracer perf = null;

        try {
            Map<String, Object> uniqueAttributes = getAttributes(servletRequest);

            if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityREST.partialUpdateEntityByUniqueAttrs(" + typeName + "," + uniqueAttributes + ")");
            }

            AtlasEntityType entityType = ensureEntityType(typeName);

            validateUniqueAttribute(entityType, uniqueAttributes);

            return entitiesStore.updateByUniqueAttributes(entityType, uniqueAttributes, entityInfo);
        } finally {
            AtlasPerfTracer.log(perf);
        }
    }
505861
public PactDslRequestWithoutPath body(String body, ContentType mimeType) {
        return body(body, mimeType.toString());
    }
685652
public void readWriteVar(Class<?> type,String varName,StringBuilder writesb,StringBuilder readsb,boolean nullCheck,Type ...actualType)
	{
//		if(type.isArray())
//		{//数组不支持泛型
//			Class<?> ctype=type.getComponentType();
//			String varTypeName=getVarTypeName(type);
//			String i=varName+"_i";
//			String var_data=varName+"_d";
//			String var_dataTypeName=getVarTypeName(ctype);
//			String var_len=varName+"_l";
//			
//			if(nullCheck)
//			{
//				writesb.append("\t").append("if (" + varName + "!=null){").append("\n");
//				writesb.append("\t").append("buffer.writeBoolean(true);").append("\n");
//				
//				readsb.append("\t").append("if (buffer.readBoolean()){").append("\n");
//			}
//			writesb.append("\t").append("int "+var_len+"="+varName+".length;").append("\n");
//			writesb.append("\t").append("buffer.writeInt("+var_len+");").append("\n");
//			writesb.append("\t").append("for(int "+i +"=0;" +i+"<"+var_len+";"+i+"++){").append("\n");
//			writesb.append("\t").append(var_dataTypeName+" "+var_data+"="+varName+"["+i+"];").append("\n");
//			
//			readsb.append("\t").append("int "+var_len+"=buffer.readInt();").append("\n");
//			readsb.append("\t").append(varName+"=("+varTypeName+") java.lang.reflect.Array.newInstance("+var_dataTypeName+".class,"+var_len+");").append("\n");
//			readsb.append("\t").append("for(int "+i +"=0;" +i+"<"+var_len+";"+i+"++){").append("\n");
//			readsb.append("\t").append(var_dataTypeName+" "+var_data+";").append("\n");
//			//读写变量
//			readWriteVar_Base(ctype, var_data, writesb, readsb, false);
//			//设置值
//			readsb.append("\t").append(varName+"["+i+"]="+var_data+";").append("\n");
//			
//			writesb.append("\t").append("}").append("\n");
//			readsb.append("\t").append("}").append("\n");
//			
//			if(nullCheck)
//			{
//				writesb.append("\t").append("}else{");
//				writesb.append("\t").append("buffer.writeBoolean(false);}").append("\n");
//				
//				readsb.append("\t").append("}").append("\n");
//			}
//			return ;
//		}
		if(Map.class.isAssignableFrom(type))
		{
			Type keyType_=actualType[0];
			Type valueType_=actualType[1];
			Class<?> keyType=null;
			Class<?> valueType=null;
			Type[] keyTypeActs=new Type[]{};
			Type[] valueTypeActs=new Type[]{};
			if(keyType_ instanceof ParameterizedType) 
			{
				ParameterizedType pt=(ParameterizedType)keyType_;
				keyType=(Class<?>)pt.getRawType();
				keyTypeActs=pt.getActualTypeArguments();
			}else
			{
				keyType=(Class<?>)keyType_;
			}
			if(valueType_ instanceof ParameterizedType) 
			{
				ParameterizedType pt=(ParameterizedType)valueType_;
				valueType=(Class<?>)pt.getRawType();
				valueTypeActs=pt.getActualTypeArguments();
			}else
			{
				valueType=(Class<?>)valueType_;
			}
			String var_mapSize=varName+"_ms";
			String var_mapI=varName+"_mi";
			String var_mapKey=varName+"_mk";
			String var_mapValue=varName+"_mv";
			
			String var_mapKeyType=getVarTypeName(keyType,keyTypeActs);
			String var_mapValueType=getVarTypeName(valueType,valueTypeActs);
			String varInstanceType=type.getCanonicalName();
			if(type==Map.class)
			{
				varInstanceType="java.util.HashMap";
			}
			
			if(nullCheck)
			{
				writesb.append("\t").append("if (" + varName + "!=null){").append("\n");
				writesb.append("\t").append("buffer.writeBoolean(true);").append("\n");
				
				readsb.append("\t").append("if (buffer.readBoolean()){").append("\n");
			}
			writesb.append("\t").append("int "+var_mapSize+"="+varName+".size();").append("\n");
			writesb.append("\t").append("buffer.writeInt("+var_mapSize+");").append("\n");
			writesb.append("\t").append("for("+var_mapKeyType+" "+var_mapKey +":" +varName+".keySet()){").append("\n");
			writesb.append("\t").append(var_mapValueType+" "+var_mapValue+"="+varName+".get("+var_mapKey+");").append("\n");
			
			readsb.append("\t").append("int "+var_mapSize+"=buffer.readInt();").append("\n");
			readsb.append("\t").append(varName+"=new "+varInstanceType+"<>();").append("\n");
			readsb.append("\t").append("for(int "+var_mapI +"=0;" +var_mapI+"<"+var_mapSize+";"+var_mapI+"++){").append("\n");
				
			//声明变量
			readsb.append("\t").append(var_mapKeyType+" "+var_mapKey+";").append("\n");
			readsb.append("\t").append(var_mapValueType+" "+var_mapValue+";").append("\n");
			
			//读写变量
			if(keyTypeActs.length>0)
			{
				readWriteVar(keyType, var_mapKey, writesb, readsb, false,keyTypeActs);
			}else
			{
				readWriteVar_Base(keyType, var_mapKey, writesb, readsb, false);
			}
			if(valueTypeActs.length>0)
			{
				readWriteVar(valueType, var_mapValue, writesb, readsb, false,valueTypeActs);
			}else
			{
				readWriteVar_Base(valueType, var_mapValue, writesb, readsb, false);
			}
			
			//设置值
			readsb.append("\t").append(varName+".put("+var_mapKey+","+var_mapValue+");").append("\n");
			
			writesb.append("\t").append("}").append("\n");
			readsb.append("\t").append("}").append("\n");
			
		    if(nullCheck)
			{
				writesb.append("\t").append("}else{");
				writesb.append("\t").append("buffer.writeBoolean(false);}").append("\n");
				
				readsb.append("\t").append("}").append("\n");
			}
			return ;
		}
		if(Collection.class.isAssignableFrom(type))
		{
			Type valueType_=actualType[0];
			Class<?> valueType=null;
			Type[] valueTypeActs=new Type[]{};
			if(valueType_ instanceof ParameterizedType) 
			{
				ParameterizedType pt=(ParameterizedType)valueType_;
				valueType=(Class<?>)pt.getRawType();
				valueTypeActs=pt.getActualTypeArguments();
			}else
			{
				valueType=(Class<?>)valueType_;
			}
			
			String var_listSize=varName+"_ls";
			String var_listI=varName+"_li";
			String var_listValue=varName+"_lv";
			String var_listValueType=getVarTypeName(valueType,valueTypeActs);
			
			String varInstanceType=type.getCanonicalName();
			if(List.class.isAssignableFrom(type))
			{
				if(type==List.class)
				{
					varInstanceType="java.util.ArrayList";
				}
			}
			if(Queue.class.isAssignableFrom(type))
			{
				if(type==Queue.class)
				{
					varInstanceType="java.util.concurrent.ConcurrentLinkedQueue";
				}
			}
			if(Set.class.isAssignableFrom(type))
			{
				if(type==Set.class)
				{
					varInstanceType="java.util.HashSet";
				}
			}
			if(nullCheck)
			{
				writesb.append("\t").append("if (" + varName + "!=null){").append("\n");
				writesb.append("\t").append("buffer.writeBoolean(true);").append("\n");
				
				readsb.append("\t").append("if (buffer.readBoolean()){").append("\n");
			}
			writesb.append("\t").append("int "+var_listSize+"="+varName+".size();").append("\n");
			writesb.append("\t").append("buffer.writeInt("+var_listSize+");").append("\n");
			writesb.append("\t").append("for("+var_listValueType +" "+var_listValue+":" +varName+"){").append("\n");
			
			readsb.append("\t").append("int "+var_listSize+"=buffer.readInt();").append("\n");
			
			readsb.append("\t").append(varName+"=new "+varInstanceType+"<>();").append("\n");
			
			readsb.append("\t").append("for(int "+var_listI +"=0;" +var_listI+"<"+var_listSize+";"+var_listI+"++){").append("\n");
				
			//声明变量
			readsb.append("\t").append(var_listValueType+" "+var_listValue+";").append("\n");
			
			//读写变量
			if(valueTypeActs.length>0)
			{
				readWriteVar(valueType, var_listValue, writesb, readsb, false,valueTypeActs);
			}else
			{
				readWriteVar_Base(valueType, var_listValue, writesb, readsb, false);
			}
			
			//设置值
			readsb.append("\t").append(varName+".add("+var_listValue+");").append("\n");
			
			writesb.append("\t").append("}").append("\n");
			readsb.append("\t").append("}").append("\n");
			
		    if(nullCheck)
			{
				writesb.append("\t").append("}else{");
				writesb.append("\t").append("buffer.writeBoolean(false);}").append("\n");
				
				readsb.append("\t").append("}").append("\n");
			}
			return ;
		}
		//简单类型
		readWriteVar_Base(type, varName, writesb, readsb, nullCheck);
	}
317317
public MetadataV3 fetchRoute(int version, MetadataV3 docs) {
    Route route = null;
    if (docs.path != null && docs.http_method != null) {
      try {
        route = RequestServer.lookupRoute(new RequestUri(docs.http_method, docs.path));
      } catch (MalformedURLException e) {
        route = null;
      }
    } else {
      // Linear scan for the route, plus each route is asked for in-order
      // during doc-gen leading to an O(n^2) execution cost.
      if (docs.path != null)
        try { docs.num = Integer.parseInt(docs.path); }
        catch (NumberFormatException e) { /* path is not a number, it's ok */ }
      if (docs.num >= 0 && docs.num < RequestServer.numRoutes())
        route = RequestServer.routes().get(docs.num);
      // Crash-n-burn if route not found (old code thru an AIOOBE), so we
      // something similarly bad.
      docs.routes = new RouteV3[]{new RouteV3(route)};
    }
    if (route == null) return null;

    Schema sinput, soutput;
    if( route._handler_class.equals(water.api.ModelBuilderHandler.class) ||
        route._handler_class.equals(water.api.GridSearchHandler.class)) {
      // GridSearchHandler uses the same logic as ModelBuilderHandler because there are no separate
      // ${ALGO}GridSearchParametersV3 classes, instead each field in ${ALGO}ParametersV3 is marked as either gridable
      // or not.
      String ss[] = route._url.split("/");
      String algoURLName = ss[3]; // {}/{3}/{ModelBuilders}/{gbm}/{parameters}
      String algoName = ModelBuilder.algoName(algoURLName); // gbm -> GBM; deeplearning -> DeepLearning
      String schemaDir = ModelBuilder.schemaDirectory(algoURLName);
      int version2 = Integer.valueOf(ss[1]);
      try {
        String inputSchemaName = schemaDir + algoName + "V" + version2;  // hex.schemas.GBMV3
        sinput = (Schema) TypeMap.getTheFreezableOrThrow(TypeMap.onIce(inputSchemaName));
      } catch (java.lang.ClassNotFoundException e) {
        // Not very pretty, but for some routes such as /99/Grid/glm we want to map to GLMV3 (because GLMV99 does not
        // exist), yet for others such as /99/Grid/svd we map to SVDV99 (because SVDV3 does not exist).
        sinput = (Schema) TypeMap.theFreezable(TypeMap.onIce(schemaDir + algoName + "V3"));
      }
      sinput.init_meta();
      soutput = sinput;
    } else {
      sinput  = Schema.newInstance(Handler.getHandlerMethodInputSchema (route._handler_method));
      soutput = Schema.newInstance(Handler.getHandlerMethodOutputSchema(route._handler_method));
    }
    docs.routes[0].input_schema = sinput.getClass().getSimpleName();
    docs.routes[0].output_schema = soutput.getClass().getSimpleName();
    docs.routes[0].markdown = route.markdown(sinput,soutput).toString();
    return docs;
  }
712838
private RequestBody getBody(Map<String, String> data, @Nullable Map<String, File> files, @Nullable Map<String,
            InputStream> fileStreams) throws LocalOperationException {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        if (files != null) {
            for (Map.Entry<String, File> entry : files.entrySet()) {
                File file = entry.getValue();
                String mimeType = URLConnection.guessContentTypeFromName(file.getName());

                if (mimeType == null) {
                    mimeType = "application/octet-stream";
                }

                builder.addFormDataPart(entry.getKey(), file.getName(),
                        RequestBody.create(MediaType.parse(mimeType), file));
            }
        }

        if (fileStreams != null) {
            for (Map.Entry<String, InputStream> entry : fileStreams.entrySet()) {
                byte[] bytes;
                InputStream stream = entry.getValue();
                try {
                    bytes = new byte[stream.available()];
                    stream.read(bytes);

                } catch (IOException e) {
                    throw new LocalOperationException(e);
                }
                builder.addFormDataPart(entry.getKey(), null,
                        RequestBody.create(MediaType.parse("application/octet-stream"), bytes));
            }
        }

        for (Map.Entry<String, String> entry : data.entrySet()) {
            builder.addFormDataPart(entry.getKey(), entry.getValue());
        }

        return builder.build();
    }
100567
@Deprecated
	public VPackSlice serialize(final Object entity, final Type type) throws VPackParserException {
		return serialize(entity, new SerializeOptions().type(type));
	}
376361
@ReadOperation
    public Map<String, Object> getSsoSessions(final String type) {
        val sessionsMap = new HashMap<String, Object>(1);
        val option = SsoSessionReportOptions.valueOf(type);
        val activeSsoSessions = getActiveSsoSessions(option);
        sessionsMap.put("activeSsoSessions", activeSsoSessions);
        val totalTicketGrantingTickets = new AtomicLong();
        val totalProxyGrantingTickets = new AtomicLong();
        val totalUsageCount = new AtomicLong();
        val uniquePrincipals = new HashSet<Object>();
        for (val activeSsoSession : activeSsoSessions) {
            if (activeSsoSession.containsKey(SsoSessionAttributeKeys.IS_PROXIED.toString())) {
                val isProxied = Boolean.valueOf(activeSsoSession.get(SsoSessionAttributeKeys.IS_PROXIED.toString()).toString());
                if (isProxied) {
                    totalProxyGrantingTickets.incrementAndGet();
                } else {
                    totalTicketGrantingTickets.incrementAndGet();
                    val principal = activeSsoSession.get(SsoSessionAttributeKeys.AUTHENTICATED_PRINCIPAL.toString()).toString();
                    uniquePrincipals.add(principal);
                }
            } else {
                totalTicketGrantingTickets.incrementAndGet();
                val principal = activeSsoSession.get(SsoSessionAttributeKeys.AUTHENTICATED_PRINCIPAL.toString()).toString();
                uniquePrincipals.add(principal);
            }
            val uses = Long.parseLong(activeSsoSession.get(SsoSessionAttributeKeys.NUMBER_OF_USES.toString()).toString());
            totalUsageCount.getAndAdd(uses);
        }
        sessionsMap.put("totalProxyGrantingTickets", totalProxyGrantingTickets);
        sessionsMap.put("totalTicketGrantingTickets", totalTicketGrantingTickets);
        sessionsMap.put("totalTickets", totalTicketGrantingTickets.longValue() + totalProxyGrantingTickets.longValue());
        sessionsMap.put("totalPrincipals", uniquePrincipals.size());
        sessionsMap.put("totalUsageCount", totalUsageCount);
        return sessionsMap;
    }
611839
public <R> R getData(Class<R> type) {
        return GSON.fromJson(data, type);
    }
827594
@SuppressWarnings("all")
    private static <T> T toNonCollectionType(Object data, Class<T> nonCollectionType) {
        if (Collection.class.isAssignableFrom(nonCollectionType)) {
            throw new RuntimeException("API使用错误，本方法不支持将目标对象转为非集合类型");
        }
        if (data == null) {
            return Defaults.defaultValue(nonCollectionType);
        }
        if (data.getClass().isArray()) {
            data = ArrayUtil.toList(data);
        }
        if (data instanceof Collection) {
            Collection collection = (Collection) data;
            if (nonCollectionType == String.class) {
                return (T) JSON.toJSONString(collection);
            }
            if (collection.isEmpty()) {
                return null;
            }
            if (collection.size() >= 2) {
                LOG.warn(new Throwable(String.format("集合 【 %s 】  的元素个数不只一个,我们只取出第一个做转换", data)));
            }
            for (Object element : collection) {
                LOG.debug("集合的第一个元素会被转为目标类型");
                return transferNonCollection(element, nonCollectionType);
            }
        } else {
            return transferNonCollection(data, nonCollectionType);
        }
        throw castFailedException(data, nonCollectionType);
    }
17075
@SuppressWarnings("unchecked")
    public <T> T readBodyAsObject(Class<T> type) {
        Charset charset = readCharset();
        InputStream inputStream = new ByteArrayInputStream(message.getBodyContent());
        InputStreamReader inputReader = new InputStreamReader(inputStream, charset);
        StreamSource streamSource = new StreamSource(inputReader);
        try {
            Unmarshaller unmarshaller = JAXBContext.newInstance(type).createUnmarshaller();
            if (type.isAnnotationPresent(XmlRootElement.class)) {
                return (T)unmarshaller.unmarshal(streamSource);
            } else {
                JAXBElement<T> element = unmarshaller.unmarshal(streamSource, type);
                return element.getValue();
            }
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }
804530
@SuppressWarnings("unchecked")
    public <T> T deserialize(String body, Type returnType) {
        try {
            return gson.fromJson(body, returnType);
        } catch (JsonParseException e) {
            // Fallback processing when failed to parse JSON form response body:
            // return the response body string directly for the String return
            // type;
            // parse response body into date or datetime for the Date return
            // type.
            if (returnType.equals(String.class))
                return (T) body;
            // else if (returnType.equals(Date.class))
            // return (T) apiClient.parseDateOrDatetime(body);
            else
                throw (e);
        }
    }
1187424
@SuppressWarnings("unused") // called through reflection by RequestServer
  public MetadataV3 fetchSchemaMetadata(int version, MetadataV3 docs) {
    if ("void".equals(docs.schemaname)) {
      docs.schemas = new SchemaMetadataV3[0];
      return docs;
    }

    docs.schemas = new SchemaMetadataV3[1];
    // NOTE: this will throw an exception if the classname isn't found:
    Schema schema = Schema.newInstance(docs.schemaname);
    // get defaults
    try {
      Iced impl = (Iced) schema.getImplClass().newInstance();
      schema.fillFromImpl(impl);
    }
    catch (Exception e) {
      // ignore if create fails; this can happen for abstract classes
    }
    SchemaMetadataV3 meta = new SchemaMetadataV3(new SchemaMetadata(schema));
    docs.schemas[0] = meta;
    return docs;
  }