use of org.mule.metadata.api.visitor.MetadataTypeVisitor in project mule by mulesoft.
the class CollectionSchemaDelegate method generateCollectionComplexType.
private LocalComplexType generateCollectionComplexType(DslElementSyntax collectionDsl, final ArrayType metadataType) {
final LocalComplexType collectionComplexType = new LocalComplexType();
final ExplicitGroup sequence = new ExplicitGroup();
final MetadataType genericType = metadataType.getType();
DslElementSyntax itemDsl = collectionDsl.getGeneric(genericType).orElseThrow(() -> new IllegalArgumentException(format("Missing item's DSL information for collection [%s]", collectionDsl.getAttributeName())));
genericType.accept(new MetadataTypeVisitor() {
/**
* For a Collection with an {@link ObjectType} as generic. The generated {@link ComplexType} declares a sequence of either a
* {@code ref} or a {@code choice}.
* <p/>
* It creates an element {@code ref} to the concrete element whose {@code type} is the {@link ComplexType} associated to the
* {@code objectType}
* <p/>
* In the case of having a {@link DslElementSyntax#isWrapped wrapped} {@link ObjectType}, then a {@link ExplicitGroup
* Choice} group that can receive a {@code ref} to any subtype that this wrapped type might have, be it either a top-level
* element for the mule schema, or if it can only be declared as child of this element.
*
* If the collections's value is a map, then a value attribute is created for the value map.
*
* @param objectType the item's type
*/
@Override
public void visitObject(ObjectType objectType) {
if (isMap(objectType)) {
defaultVisit(objectType);
return;
}
DslElementSyntax typeDsl = builder.getDslResolver().resolve(objectType).orElseThrow(() -> new IllegalArgumentException(format("The given type [%s] cannot be represented as a collection item", getId(objectType))));
if (typeDsl.isWrapped()) {
ExplicitGroup choice = builder.createTypeRefChoiceLocalOrGlobal(typeDsl, objectType, ZERO, UNBOUNDED);
sequence.getParticle().add(objectFactory.createChoice(choice));
} else {
TopLevelElement collectionItemElement = builder.createTypeRef(typeDsl, objectType, false);
collectionItemElement.setMaxOccurs(UNBOUNDED);
sequence.getParticle().add(objectFactory.createElement(collectionItemElement));
}
}
/**
* For a Collection with any other type as generic.
* The generated {@link ComplexType} declares a sequence of child elements with an inline declaration of the type
*
* @param metadataType the item's type
*/
@Override
protected void defaultVisit(MetadataType metadataType) {
final LocalComplexType complexType = new LocalComplexType();
complexType.getAttributeOrAttributeGroup().add(builder.createValueAttribute(genericType));
TopLevelElement collectionItemElement = builder.createTopLevelElement(itemDsl.getElementName(), ZERO, UNBOUNDED);
collectionItemElement.setComplexType(complexType);
sequence.getParticle().add(objectFactory.createElement(collectionItemElement));
}
});
collectionComplexType.setSequence(sequence);
return collectionComplexType;
}
use of org.mule.metadata.api.visitor.MetadataTypeVisitor in project mule by mulesoft.
the class ExtensionDefinitionParser method parseMapParameters.
/**
* Registers a definition for a {@link ParameterModel} which represents an open {@link ObjectType}
*
* @param key the key that the parsed value should have on the parsed parameter's map
* @param name the parameter's name
* @param dictionaryType the parameter's open {@link ObjectType}
* @param defaultValue the parameter's default value
* @param expressionSupport the parameter's {@link ExpressionSupport}
* @param required whether the parameter is required
*/
protected void parseMapParameters(String key, String name, ObjectType dictionaryType, Object defaultValue, ExpressionSupport expressionSupport, boolean required, DslElementSyntax paramDsl, Set<ModelProperty> modelProperties) {
parseAttributeParameter(key, name, dictionaryType, defaultValue, expressionSupport, required, modelProperties);
Class<? extends Map> mapType = getType(dictionaryType);
if (ConcurrentMap.class.equals(mapType)) {
mapType = ConcurrentHashMap.class;
} else if (Map.class.equals(mapType)) {
mapType = LinkedHashMap.class;
}
final MetadataType valueType = dictionaryType.getOpenRestriction().orElse(typeLoader.load(Object.class));
final Class<?> valueClass = getType(valueType);
final MetadataType keyType = typeLoader.load(String.class);
final Class<?> keyClass = String.class;
final String mapElementName = paramDsl.getElementName();
addParameter(getChildKey(key), fromChildMapConfiguration(String.class, valueClass).withWrapperIdentifier(mapElementName).withDefaultValue(defaultValue));
addDefinition(baseDefinitionBuilder.withIdentifier(mapElementName).withTypeDefinition(fromType(mapType)).build());
Optional<DslElementSyntax> mapValueChildDsl = paramDsl.getGeneric(valueType);
if (!mapValueChildDsl.isPresent()) {
return;
}
DslElementSyntax valueDsl = mapValueChildDsl.get();
valueType.accept(new MetadataTypeVisitor() {
@Override
protected void defaultVisit(MetadataType metadataType) {
String parameterName = paramDsl.getAttributeName();
addDefinition(baseDefinitionBuilder.withIdentifier(valueDsl.getElementName()).withTypeDefinition(fromMapEntryType(keyClass, valueClass)).withKeyTypeConverter(value -> resolverOf(parameterName, keyType, value, null, expressionSupport, true, emptySet(), false)).withTypeConverter(value -> resolverOf(parameterName, valueType, value, null, expressionSupport, true, emptySet(), false)).build());
}
@Override
public void visitObject(ObjectType objectType) {
defaultVisit(objectType);
Optional<DslElementSyntax> containedElement = valueDsl.getContainedElement(VALUE_ATTRIBUTE_NAME);
if (isMap(objectType) || !containedElement.isPresent()) {
return;
}
DslElementSyntax valueChild = containedElement.get();
if ((valueChild.supportsTopLevelDeclaration() || (valueChild.supportsChildDeclaration() && !valueChild.isWrapped())) && !parsingContext.isRegistered(valueChild.getElementName(), valueChild.getPrefix())) {
try {
parsingContext.registerObjectType(valueChild.getElementName(), valueChild.getPrefix(), objectType);
new ObjectTypeParameterParser(baseDefinitionBuilder, objectType, getContextClassLoader(), dslResolver, parsingContext).parse().forEach(definition -> addDefinition(definition));
} catch (ConfigurationException e) {
throw new MuleRuntimeException(createStaticMessage("Could not create parser for map complex type"), e);
}
}
}
@Override
public void visitArrayType(ArrayType arrayType) {
defaultVisit(arrayType);
Optional<DslElementSyntax> valueListGenericDsl = valueDsl.getGeneric(arrayType.getType());
if (valueDsl.supportsChildDeclaration() && valueListGenericDsl.isPresent()) {
arrayType.getType().accept(new BasicTypeMetadataVisitor() {
@Override
protected void visitBasicType(MetadataType metadataType) {
String parameterName = paramDsl.getAttributeName();
addDefinition(baseDefinitionBuilder.withIdentifier(valueListGenericDsl.get().getElementName()).withTypeDefinition(fromType(getType(metadataType))).withTypeConverter(value -> resolverOf(parameterName, metadataType, value, getDefaultValue(metadataType), getExpressionSupport(metadataType), false, emptySet())).build());
}
@Override
protected void defaultVisit(MetadataType metadataType) {
addDefinition(baseDefinitionBuilder.withIdentifier(valueListGenericDsl.get().getElementName()).withTypeDefinition(fromType(ValueResolver.class)).withObjectFactoryType(TopLevelParameterObjectFactory.class).withConstructorParameterDefinition(fromFixedValue(arrayType.getType()).build()).withConstructorParameterDefinition(fromFixedValue(getContextClassLoader()).build()).build());
}
});
}
}
});
}
use of org.mule.metadata.api.visitor.MetadataTypeVisitor in project mule by mulesoft.
the class SchemaTypeConversion method convertType.
public static QName convertType(final MetadataType type, ExpressionSupport expressionSupport) {
final boolean dynamic = acceptsExpressions(expressionSupport);
final Reference<QName> qName = new Reference<>(null);
type.accept(new MetadataTypeVisitor() {
@Override
public void visitBoolean(BooleanType booleanType) {
qName.set(dynamic ? EXPRESSION_BOOLEAN : SUBSTITUTABLE_BOOLEAN);
}
@Override
public void visitNumber(NumberType numberType) {
if (getId(numberType).isPresent()) {
Class<Number> type = JavaTypeUtils.getType(numberType);
if (anyOf(type, Integer.class, int.class)) {
qName.set(dynamic ? EXPRESSION_INTEGER : SUBSTITUTABLE_INT);
} else if (anyOf(type, Double.class, double.class)) {
qName.set(dynamic ? EXPRESSION_DOUBLE : SUBSTITUTABLE_DECIMAL);
} else if (anyOf(type, Long.class, long.class)) {
qName.set(dynamic ? EXPRESSION_LONG : SUBSTITUTABLE_LONG);
} else {
qName.set(dynamic ? EXPRESSION_DECIMAL : SUBSTITUTABLE_DECIMAL);
}
} else {
if (numberType.getAnnotation(IntAnnotation.class).isPresent()) {
qName.set(dynamic ? EXPRESSION_INTEGER : SUBSTITUTABLE_INT);
} else {
qName.set(dynamic ? EXPRESSION_DECIMAL : SUBSTITUTABLE_DECIMAL);
}
}
}
@Override
public void visitString(StringType stringType) {
qName.set(dynamic ? EXPRESSION_STRING : STRING);
}
@Override
public void visitDateTime(DateTimeType dateTimeType) {
onDate();
}
@Override
public void visitDate(DateType dateType) {
onDate();
}
@Override
public void visitArrayType(ArrayType arrayType) {
qName.set(dynamic ? EXPRESSION_LIST : SUBSTITUTABLE_NAME);
}
@Override
public void visitObject(ObjectType objectType) {
if (isMap(objectType)) {
qName.set(dynamic ? EXPRESSION_MAP : SUBSTITUTABLE_NAME);
} else {
defaultVisit(objectType);
}
}
@Override
protected void defaultVisit(MetadataType metadataType) {
qName.set(STRING);
}
private void onDate() {
qName.set(dynamic ? EXPRESSION_DATE_TIME : SUBSTITUTABLE_DATE_TIME);
}
private boolean anyOf(Class<Number> type, Class<?>... targets) {
for (Class<?> target : targets) {
if (type.equals(target)) {
return true;
}
}
return false;
}
});
return qName.get();
}
use of org.mule.metadata.api.visitor.MetadataTypeVisitor in project mule by mulesoft.
the class InputParametersTypeModelValidator method validateType.
private void validateType(String message, NamedObject namedObject, MetadataType type, ProblemsReporter problems, Set<Class<?>> validatedTypes) {
ReflectionCache reflectionCache = new ReflectionCache();
getClassForValidation(type).ifPresent(parameterType -> type.accept(new MetadataTypeVisitor() {
@Override
public void visitObject(ObjectType objectType) {
if (validatedTypes.add(parameterType)) {
Collection<ObjectFieldType> parameters = objectType.getFields();
Set<String> fieldsWithGetters = getFieldsWithGetters(parameterType, reflectionCache).stream().map(TypeUtils::getAlias).map(String::toLowerCase).collect(toSet());
Set<String> parameterWithoutGetters = parameters.stream().filter(p -> {
StereotypeTypeAnnotation stereotypes = p.getAnnotation(StereotypeTypeAnnotation.class).orElse(null);
return stereotypes != null ? stereotypes.getAllowedStereotypes().isEmpty() : true;
}).map(f -> f.getKey().getName().getLocalPart()).filter(fieldName -> !fieldsWithGetters.contains(fieldName.toLowerCase())).collect(toSet());
if (!parameterWithoutGetters.isEmpty()) {
problems.addError(new Problem(namedObject, format("%s of type '%s' which contains fields (%s) that doesn't have the corresponding getter methods or getter methods that doesn't correspond to any of the present fields", message, parameterType.getName(), parameterWithoutGetters.stream().collect(joining(", ")))));
}
}
}
@Override
public void visitArrayType(ArrayType arrayType) {
validateType(message, namedObject, arrayType.getType(), problems, validatedTypes);
}
}));
}
use of org.mule.metadata.api.visitor.MetadataTypeVisitor in project mule by mulesoft.
the class NullSafeModelValidator method validate.
@Override
public void validate(ExtensionModel extensionModel, ProblemsReporter problemsReporter) {
ReflectionCache reflectionCache = new ReflectionCache();
TypeLoader typeLoader = ExtensionsTypeLoaderFactory.getDefault().createTypeLoader();
new ExtensionWalker() {
@Override
public void onParameter(ParameterizedModel owner, ParameterGroupModel groupModel, ParameterModel model) {
model.getType().accept(new MetadataTypeVisitor() {
@Override
public void visitObject(ObjectType objectType) {
if (objectType.getMetadataFormat().equals(JAVA) && !isMap(objectType)) {
objectType.getAnnotation(TypeIdAnnotation.class).map(TypeIdAnnotation::getValue).ifPresent(typeId -> typeLoader.load(typeId).ifPresent(fieldMetadataType -> objectType.getFields().stream().filter(f -> f.getAnnotation(NullSafeTypeAnnotation.class).isPresent()).forEach(f -> validateField(getLocalPart(f), f, getType(fieldMetadataType), f.getAnnotation(NullSafeTypeAnnotation.class).get()))));
}
}
private void validateField(String fieldName, ObjectFieldType field, Class<?> declaringClass, NullSafeTypeAnnotation nullSafeTypeAnnotation) {
Class<?> nullSafeType = nullSafeTypeAnnotation.getType();
Class<?> fieldType = getType(field.getValue());
boolean hasDefaultOverride = nullSafeTypeAnnotation.hasDefaultOverride();
field.getValue().accept(new BasicTypeMetadataVisitor() {
@Override
protected void visitBasicType(MetadataType metadataType) {
problemsReporter.addError(new Problem(extensionModel, format("Field '%s' in class '%s' is annotated with '@%s' but is of type '%s'. That annotation can only be " + "used with complex types (Pojos, Lists, Maps)", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
@Override
public void visitArrayType(ArrayType arrayType) {
if (hasDefaultOverride) {
problemsReporter.addError(new Problem(extensionModel, format("Field '%s' in class '%s' is annotated with '@%s' is of type '%s'" + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for Collections", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
}
@Override
public void visitObject(ObjectType objectType) {
String requiredFields = objectType.getFields().stream().filter(f -> f.isRequired() && !isFlattenedParameterGroup(f)).map(MetadataTypeUtils::getLocalPart).collect(joining(", "));
if (!isBlank(requiredFields) && isCompiletime(extensionModel)) {
problemsReporter.addError(new Problem(model, format("Class '%s' cannot be used with '@%s' parameter since it contains non optional fields: [%s]", getId(objectType).orElse(""), NullSafe.class.getSimpleName(), requiredFields)));
}
if (objectType.isOpen()) {
if (hasDefaultOverride) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' is of type '%s'" + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for Maps", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
return;
}
if (hasDefaultOverride && isInstantiable(fieldType, reflectionCache)) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' is of concrete type '%s'," + " but a 'defaultImplementingType' was provided." + " Type override is not allowed for concrete types", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName())));
}
if (!isInstantiable(nullSafeType, reflectionCache)) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' but is of type '%s'. That annotation can only be " + "used with complex instantiable types (Pojos, Lists, Maps)", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), nullSafeType.getName())));
}
if (hasDefaultOverride && !fieldType.isAssignableFrom(nullSafeType)) {
problemsReporter.addError(new Problem(model, format("Field '%s' in class '%s' is annotated with '@%s' of type '%s', but provided type '%s" + " is not a subtype of the parameter's type", fieldName, declaringClass.getName(), NullSafe.class.getSimpleName(), fieldType.getName(), nullSafeType.getName())));
}
}
});
}
});
}
}.walk(extensionModel);
}
Aggregations