001/** 002 * Copyright (C) 2006-2024 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.tools.validator; 017 018import static java.lang.String.format; 019import static java.lang.String.join; 020import static java.util.Arrays.asList; 021import static org.talend.sdk.component.tools.validator.RecordValidator.getFullName; 022import static org.talend.sdk.component.tools.validator.RecordValidator.isProducing; 023 024import java.lang.reflect.Method; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Set; 030import java.util.stream.Stream; 031 032import org.apache.xbean.finder.AnnotationFinder; 033import org.talend.sdk.component.api.record.Schema; 034 035public class SchemaValidator implements Validator { 036 037 @Override 038 public Stream<String> validate(final AnnotationFinder finder, final List<Class<?>> components) { 039 final List<String> messages = new ArrayList<>(); 040 components.stream() 041 .forEach(component -> { 042 messages.addAll(this.validateMethods(component.getDeclaredMethods(), Schema.Builder.class)); 043 messages.addAll(this.validateMethods(component.getDeclaredMethods(), Schema.Entry.Builder.class)); 044 }); 045 return messages.stream(); 046 } 047 048 private List<String> validateMethods(final Method[] methods, final Class checkClass) { 049 final List<String> messages = new ArrayList<>(); 050 051 Arrays.stream(methods) 052 .forEach(method -> { 053 if (isProducing(method, checkClass) && !isSafeEntryBuilderProvider(method)) { 054 final String errorMessage = join("\n", asList( 055 format("Method %s calls unsafe Builder creator. This either means:", 056 getFullName(method)), 057 " * That the TCK method is safe and should belong to WHITE_LIST_TCK_SCHEMA_BUILDER_PROVIDER")); 058 System.err.println("--" + getFullName(method)); 059 messages.add(errorMessage); 060 } 061 }); 062 return messages; 063 } 064 065 private static boolean isSafeEntryBuilderProvider(final Method method) { 066 return WHITE_LIST_TCK_SCHEMA_BUILDER_PROVIDER.contains(getFullName(method)); 067 } 068 069 private static final Set<String> WHITE_LIST_TCK_SCHEMA_BUILDER_PROVIDER = new HashSet<>(asList( 070 "org.talend.sdk.component.runtime.record.SchemaImpl.toBuilder()", 071 "org.talend.sdk.component.runtime.record.Schemas.moveBefore(java.lang.String, java.lang.String)", 072 "org.talend.sdk.component.runtime.record.Schemas.withType(org.talend.sdk.component.api.record.Schema$Type)", 073 "org.talend.sdk.component.runtime.record.Schemas.withEntry(org.talend.sdk.component.api.record.Schema$Entry)", 074 "org.talend.sdk.component.runtime.record.Schemas.withElementSchema(org.talend.sdk.component.api.record.Schema)", 075 "org.talend.sdk.component.api.record.Schema$Entry.toBuilder()", 076 "org.talend.sdk.component.api.record.Schema$Entry$Builder.withNullable(boolean)", 077 "org.talend.sdk.component.api.record.Schema$Entry$Builder.withMetadata(boolean)", 078 "org.talend.sdk.component.api.record.Schema$Entry$Builder.withProps(java.util.Map)", 079 "org.talend.sdk.component.api.record.Schema$Entry$Builder.withName(java.lang.String)", 080 "org.talend.sdk.component.api.record.Schema$Entry$Builder.withRawName(java.lang.String)", 081 "org.talend.sdk.component.api.record.Schema$Entry$Builder.withType(org.talend.sdk.component.api.record.Schema$Type)", 082 "org.talend.sdk.component.api.record.Schema$Builder.remove(java.lang.String)", 083 "org.talend.sdk.component.api.record.Schema$Builder.remove(org.talend.sdk.component.api.record.Schema$Entry)", 084 "org.talend.sdk.component.api.record.Schema$Builder.swap(java.lang.String, java.lang.String)", 085 "org.talend.sdk.component.api.record.Schema$Builder.withEntryBefore(java.lang.String, org.talend.sdk.component.api.record.Schema$Entry)", 086 "org.talend.sdk.component.api.record.Schema$Builder.moveBefore(java.lang.String, java.lang.String)", 087 "org.talend.sdk.component.api.record.Schema$Builder.moveAfter(java.lang.String, java.lang.String)", 088 "org.talend.sdk.component.api.record.Schema$Builder.withEntryAfter(java.lang.String, org.talend.sdk.component.api.record.Schema$Entry)", 089 "org.talend.sdk.component.api.record.Schema$Builder.withType(org.talend.sdk.component.api.record.Schema$Type)", 090 "org.talend.sdk.component.api.record.Schema$Builder.withProp(java.lang.String, java.lang.String)", 091 "org.talend.sdk.component.api.record.Schema$Builder.withEntry(org.talend.sdk.component.api.record.Schema$Entry)", 092 "org.talend.sdk.component.api.record.Schema$Builder.withProps(java.util.Map)", 093 "org.talend.sdk.component.api.record.Schema$Builder.withElementSchema(org.talend.sdk.component.api.record.Schema)", 094 "org.talend.sdk.component.api.service.schema.Schema$Entry.toBuilder()", 095 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl.toBuilder()", 096 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withNullable(boolean)", 097 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withMetadata(boolean)", 098 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withProps(java.util.Map)", 099 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withName(java.lang.String)", 100 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withRawName(java.lang.String)", 101 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withComment(java.lang.String)", 102 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withDefaultValue(java.lang.Object)", 103 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withProp(java.lang.String, java.lang.String)", 104 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withType(org.talend.sdk.component.api.record.Schema$Type)", 105 "org.talend.sdk.component.runtime.record.SchemaImpl$EntryImpl$BuilderImpl.withElementSchema(org.talend.sdk.component.api.record.Schema)")); 106 107}