M
Mart
Gast
ich hab ja meine lib gebaut und über reflektion löse ich die Annotationen auf dafür gibts den field handler
dieser ist jedoch testbar wie noch was... ergo 0
ich dneke man könnte hier noch eine klasse raus ziehen nur ich stell mich wieder an ... ich weis nicht woran ich überhaupt setzen muss in diesem fall
RmBuilder macht einfach nur strings in dem format "=> XXX => information"
und der Rconnector bindet dann die properties die vom field handler kommen
vllt die felder in records packen?
Java:
/**
* The Class FieldHandler for resolving {@link RapidfxAutoGenerate} Annotations
* and starting to Resolve {@link RapidfxModel} and {@link RapidfxController} Annotations.
*
* @param <T> the generic type
*/
public class FieldHandler<T> {
private final Field field;
private final Object objectToGetValues;
private final Class<?> fieldClass;
/**
* Instantiates a new field handler.
*
* @param field the field
* @param objectToGetValues the object to get values
*/
public FieldHandler(Field field, Object objectToGetValues) {
this.field = field;
this.field.setAccessible(true);
this.fieldClass = field.getType();
this.objectToGetValues = objectToGetValues;
}
/**
* Works with {@link Property}
* {@link Property#bind(javafx.beans.value.ObservableValue)} {@link Property}
* and with {@link PropertySetError} {@link Property#setValue(Object)}
* {@link EventHandler} and {@link Property}
* {@link Property#addListener(javafx.beans.value.ChangeListener)}
* {@link ChangeListener}.
*
* @param bindTo the Property where it should be bound to
*/
public void bindProperties(final Object bindTo) {
final var bindToField = this.findFieldWithSameName(bindTo);
if (isNull()) {
isEmptyFieldErrorMessage(field);
return;
}
if (isNull(bindToField, bindTo)) {
isEmptyFieldErrorMessage(bindToField);
return;
}
launchConnector(bindTo, bindToField);
}
private void launchConnector(final Object bindTo, final Field bindToField) {
final var connector = new RapidConnector(bindToField, bindTo);
final var viewProperty = castToReadOnlyProperty();
connector.setPropertyFrom(field, viewProperty);
connector.connectProperties();
}
private void isEmptyFieldErrorMessage(final Field bindToField) {
throw new RapidfxRuntimeException(
"\nThe Value of the Field which should be a Property/EventHandler/ChangeListener is null,"
+ " can't bind to null" + RmBuilder.name(bindToField.getName())
+ RmBuilder.clazz(bindToField.getDeclaringClass())
+ RmBuilder.type(bindToField.getType()) + "\n");
}
/**
* Sets the default value for a Property, which is SimpleXXXProperty.
*/
public void setDefaultValue() {
try {
if (!isClassTypeOfProperty()) {
castToPropertyErrorMessage("Property");
} else if (isNull()) {
field.set(objectToGetValues, getDefaultValue());
}
} catch (IllegalAccessException e) {
illegalAccessArgumentErrorMessage(e);
}
}
private void illegalAccessArgumentErrorMessage(Exception e) {
throw new RapidfxRuntimeException(
"\nThe Field was not accessible to set a RautoGenerate value ,"
+ " probably caused by the Module-info doesn't open/exports the Package"
+ RmBuilder.name(field.getName()) + RmBuilder.clazz(field.getDeclaringClass())
+ RmBuilder.type(field.getType()) + "\n" + e.getMessage());
}
/**
* Checks if is annotation present.
*
* @param annotation the annotation
* @return true, if is annotation present
*/
public boolean isAnnotationPresent(final Class<? extends Annotation> annotation) {
return this.field.isAnnotationPresent(annotation);
}
private Object getObject(Field fields, Object comp) {
field.setAccessible(true);
try {
return fields.get(comp);
} catch (IllegalArgumentException | IllegalAccessException e) {
illegalAccessArgumentErrorMessage(e);
return null;
}
}
private Field findFieldWithSameName(final Object bindTo) {
final var fieldName = field.getName().intern();
try {
final var foundField = bindTo.getClass().getDeclaredField(fieldName);
foundField.setAccessible(true);
return foundField;
} catch (NoSuchFieldException e) {
throw new RapidfxRuntimeException("\nThe Field was not found"
+ "\nThis can be caused when the Module-Info doesn't \"open PACKAGENAME\" "
+ "where the Class is Part of" + RmBuilder.name(fieldName)
+ RmBuilder.clazz(bindTo.getClass()) + RmBuilder.build(field.getType(), "EXPECTED_TYPE")
+ "\n");
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
}
}
private boolean isNull(Field fields, Object comp) {
return getObject(fields, comp) == null;
}
private boolean isNull() {
return isNull(this.field, this.objectToGetValues);
}
/**
* Checks if is class type of property.
*
* @return true, if is class type of property
*/
private boolean isClassTypeOfProperty() {
return Property.class.isAssignableFrom(this.fieldClass);
}
private final Object getDefaultValue() {
try {
final var t = Class
.forName(field.getType().getPackageName() + ".Simple" + field.getType().getSimpleName());
return t.getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException e) {
throw new RapidfxRuntimeException(
"\nDuring the try to set a default value an Exception Occured"
+ "\nIf your Object is of Type ObjectProperty "
+ "then it will get set to New SimpleXXXProperty, "
+ "only properties with Simple at the start work with this generation"
+ "\nSet the values manually to avoid that, "
+ "as only Fields with <B>value<B> null are affected"
+ "\n as the binding will still Work with any Properties "
+ "or something else went wrong while setting the default value"
+ RmBuilder.name(field.getName()) + RmBuilder.type(field.getType())
+ RmBuilder.build(field.getType().getPackageName() + " + .Simple + "
+ field.getType().getSimpleName(), "SEARCHED")
+ "\n");
}
}
private ReadOnlyProperty<?> castToReadOnlyProperty() {
return (ReadOnlyProperty<?>) getObject(this.field, this.objectToGetValues);
}
private void castToPropertyErrorMessage(String whatCast) {
throw new RapidfxRuntimeException(
"\nCouldn't cast the Field to a " + whatCast + RmBuilder.name(field.getName())
+ RmBuilder.clazz(field.getDeclaringClass()) + RmBuilder.type(field.getType()));
}
}
ich dneke man könnte hier noch eine klasse raus ziehen nur ich stell mich wieder an ... ich weis nicht woran ich überhaupt setzen muss in diesem fall
RmBuilder macht einfach nur strings in dem format "=> XXX => information"
und der Rconnector bindet dann die properties die vom field handler kommen
vllt die felder in records packen?