org.dellroad.stuff.vaadin8.ProvidesPropertyScanner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dellroad-stuff-vaadin8 Show documentation
Show all versions of dellroad-stuff-vaadin8 Show documentation
DellRoad Stuff classes related to Vaadin 8.x.
The newest version!
/*
* Copyright (C) 2022 Archie L. Cobbs. All rights reserved.
*/
package org.dellroad.stuff.vaadin8;
import com.vaadin.data.PropertySet;
import com.vaadin.util.ReflectTools;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.dellroad.stuff.java.MethodAnnotationScanner;
import org.dellroad.stuff.java.ReflectUtil;
/**
* Scans a Java class hierarchy for {@link ProvidesProperty @ProvidesProperty} annotated getter methods and creates
* a corresponding {@link com.vaadin.data.PropertySet} containing {@link com.vaadin.data.PropertyDefinition}s
* that extract property values from instances of the given class via the annotated methods.
*
* @param Java class to be introspected
* @see ProvidesProperty @ProvidesProperty
*/
public class ProvidesPropertyScanner {
private final SimplePropertySet propertySet;
/**
* Constructor.
*
* @param type Java class to be introspected
* @throws IllegalArgumentException if {@code type} is null
* @throws IllegalArgumentException if an annotated method with no {@linkplain ProvidesProperty#value property name specified}
* has a name which cannot be interpreted as a bean property "getter" method
* @throws IllegalArgumentException if {@code type} has two {@link ProvidesProperty @ProvidesProperty}-annotated
* fields or methods with the same {@linkplain ProvidesProperty#value property name}
*/
public ProvidesPropertyScanner(Class type) {
// Sanity check
if (type == null)
throw new IllegalArgumentException("null type");
this.propertySet = new SimplePropertySet<>(type);
// Scan for @ProvidesProperty annotations
final Set.MethodInfo> providesPropertyMethods
= new MethodAnnotationScanner<>(type, ProvidesProperty.class).findAnnotatedMethods();
// Check for duplicate @ProvidesProperty names
final Comparator methodComparator = Comparator.comparing(Method::getDeclaringClass,
ReflectUtil.getClassComparator(false));
final HashMap.MethodInfo> providesPropertyNameMap = new HashMap<>();
for (MethodAnnotationScanner.MethodInfo methodInfo : providesPropertyMethods) {
final String propertyName = this.getPropertyName(methodInfo);
// Check for name conflict
final MethodAnnotationScanner.MethodInfo previousInfo = providesPropertyNameMap.get(propertyName);
if (previousInfo == null) {
providesPropertyNameMap.put(propertyName, methodInfo);
continue;
}
// If there is a name conflict, the sub-type method declaration wins
switch (methodComparator.compare(previousInfo.getMethod(), methodInfo.getMethod())) {
case 0:
throw new IllegalArgumentException("duplicate @" + ProvidesProperty.class.getSimpleName()
+ " declaration for property `" + propertyName + "' on method " + previousInfo.getMethod()
+ " and " + methodInfo.getMethod() + " declared in the same class");
case 1:
providesPropertyNameMap.put(propertyName, methodInfo);
break;
default:
break;
}
}
// Build PropertyDefinition list
for (Map.Entry.MethodInfo> e : providesPropertyNameMap.entrySet()) {
final String name = e.getKey();
final MethodAnnotationScanner.MethodInfo methodInfo = e.getValue();
// Get property caption
final String caption = this.getPropertyCaption(methodInfo);
// Get property type
Class> propertyType = methodInfo.getMethod().getReturnType();
// Add property definition
this.propertySet.add(ReflectTools.convertPrimitiveType(propertyType),
name, caption, methodInfo.getMethod(), methodInfo.getSetter());
}
}
/**
* Get the {@link com.vaadin.data.PropertySet} generated from the annotated methods.
*
* @return property set
*/
public PropertySet getPropertySet() {
return this.propertySet;
}
/**
* Get the property name.
*
* @param methodInfo method info
* @return property name
*/
protected String getPropertyName(MethodAnnotationScanner.MethodInfo methodInfo) {
return methodInfo.getAnnotation().value().length() > 0 ?
methodInfo.getAnnotation().value() : methodInfo.getMethodPropertyName();
}
/**
* Get the property caption.
*
* @param methodInfo method info
* @return property caption
*/
protected String getPropertyCaption(MethodAnnotationScanner.MethodInfo methodInfo) {
return methodInfo.getAnnotation().caption().length() > 0 ?
methodInfo.getAnnotation().caption() : this.getPropertyName(methodInfo);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy