io.qt.internal.MetaObjectUtility Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qtjambi Show documentation
Show all versions of qtjambi Show documentation
QtJambi base module containing QtCore, QtGui and QtWidgets.
/****************************************************************************
**
** Copyright (C) 2009-2024 Dr. Peter Droste, Omix Visualization GmbH & Co. KG. All rights reserved.
**
** This file is part of Qt Jambi.
**
** $BEGIN_LICENSE$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
** $END_LICENSE$
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
package io.qt.internal;
import static io.qt.internal.EnumUtility.getEnumForQFlags;
import static io.qt.internal.MetaTypeUtility.findMetaType;
import static io.qt.internal.MetaTypeUtility.internalTypeNameOfClass;
import static io.qt.internal.MetaTypeUtility.registerMetaType;
import static io.qt.internal.MetaTypeUtility.registerRefMetaType;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.logging.Logger;
import io.qt.NativeAccess;
import io.qt.QFlags;
import io.qt.QPropertyDeclarationException;
import io.qt.QSignalDeclarationException;
import io.qt.QSignalInitializationException;
import io.qt.QtAsGadget;
import io.qt.QtByteEnumerator;
import io.qt.QtClassInfo;
import io.qt.QtEnumerator;
import io.qt.QtInvokable;
import io.qt.QtLongEnumerator;
import io.qt.QtMetaType;
import io.qt.QtPointerType;
import io.qt.QtPropertyConstant;
import io.qt.QtPropertyDesignable;
import io.qt.QtPropertyMember;
import io.qt.QtPropertyNotify;
import io.qt.QtPropertyReader;
import io.qt.QtPropertyRequired;
import io.qt.QtPropertyResetter;
import io.qt.QtPropertyScriptable;
import io.qt.QtPropertyStored;
import io.qt.QtPropertyUser;
import io.qt.QtPropertyWriter;
import io.qt.QtReferenceType;
import io.qt.QtShortEnumerator;
import io.qt.QtUninvokable;
import io.qt.QtUnlistedEnum;
import io.qt.core.QDeclarableSignals;
import io.qt.core.QMetaObject;
import io.qt.core.QMetaType;
import io.qt.core.QObject;
import io.qt.core.QPair;
import io.qt.core.QStaticMemberSignals;
import io.qt.internal.SignalUtility.SignalParameterType;
/**
* Methods to help construct the fake meta object.
* @hidden
*/
final class MetaObjectUtility extends AbstractMetaObjectUtility{
private MetaObjectUtility() { throw new RuntimeException();}
private final static boolean isQt6 = QtJambi_LibraryUtilities.qtMajorVersion>5;
static Function super K, ArrayList> arrayListFactory(){
return key->new ArrayList<>();
}
/**
* this method analyzes the given class for meta object data.
* It is based upon code of the moc tool.
*/
@NativeAccess
private static MetaObjectData analyze(Class> clazz) {
int revision = resolveMetaDataRevision();
try {
if(clazz.isPrimitive()) {
throw new RuntimeException("Cannot analyze meta object from primitive type");
}
else if(clazz.isArray()) {
throw new RuntimeException("Cannot analyze meta object from array type");
}
MetaObjectData metaObjectData = new MetaObjectData();
metaObjectData.addStringDataAndReturnIndex("Reserving the first string for QDynamicMetaObject identification.");
List intdataComments = /*new ArrayList<>();*/new AbstractList() {
@Override
public boolean add(String e) { return false; }
@Override
public String get(int index) {return null;}
@Override
public int size() {return 0; }
};
final String classname = clazz.getName().replace(".", "::").replace("$", "::");
Hashtable classInfos = new Hashtable();
for(QtClassInfo info : clazz.getAnnotationsByType(QtClassInfo.class)) {
classInfos.put(info.key(), info.value());
}
if(qmlClassInfoGeneratorFunction!=null) {
classInfos.putAll(qmlClassInfoGeneratorFunction.apply(clazz));
}
Map methodFlags = new HashMap<>();
Map propertyReaders = new TreeMap<>();
Map> propertyWriters = new TreeMap<>();
Map propertyDesignableResolvers = new TreeMap<>();
Map propertyScriptableResolvers = new TreeMap<>();
Map propertyEditableResolvers = new TreeMap<>();
Map propertyStoredResolvers = new TreeMap<>();
Map propertyUserResolvers = new TreeMap<>();
Map propertyRequiredResolvers = new TreeMap<>();
Map propertyConstantResolvers = new TreeMap<>();
Map propertyFinalResolvers = new TreeMap<>();
Map propertyResetters = new TreeMap<>();
Map propertyNotifies = new TreeMap<>();
Map propertyBindables = new TreeMap<>();
Map propertyMembers = new TreeMap<>();
Map propertyQPropertyFields = new TreeMap<>();
Map signals = new TreeMap<>();
// First we get all enums actually declared in the class
Map> enums = findFlagsAndEnums(clazz);
class ParameterInfo{
public ParameterInfo(int metaTypeId, String typeName) {
super();
this.type = null;
this.metaTypeId = metaTypeId;
this.typeName = typeName;
}
public ParameterInfo(io.qt.core.QMetaType.Type type) {
super();
this.type = type;
this.metaTypeId = 0;
this.typeName = null;
}
final QMetaType.Type type;
final int metaTypeId;
final String typeName;
}
Set addedMethodSignatures = new TreeSet<>();
List signalIsClone = new ArrayList<>();
List> allSignalParameterInfos = new ArrayList<>();
boolean isQObject = QObject.class.isAssignableFrom(clazz);
boolean isGadget = clazz.isAnnotationPresent(QtAsGadget.class);
if(isQObject && isGadget){
throw new IllegalStateException("Must not annotate QObject type '"+clazz.getTypeName()+"' with @QtAsGadget.");
}
if(!isQObject && !isGadget){
isGadget = gadgetClasses.contains(clazz) || gadgetPackages.contains(clazz.getPackage().getName());
}
{
try {
Class> syntheticClass = Class.forName(clazz.getName()+"$WhenMappings", false, clazz.getClassLoader());
if(syntheticClass.isSynthetic()) {
for(Field declaredField : syntheticClass.getDeclaredFields()) {
if(Modifier.isStatic(declaredField.getModifiers())
&& declaredField.getType()==int[].class
&& declaredField.getName().startsWith("$EnumSwitchMapping$")) {
metaObjectData.switchTableFields.add(declaredField);
}
}
}
} catch (Throwable e1) {
}
for(int i=1;;++i) {
try {
Class> syntheticClass = Class.forName(clazz.getName()+"$"+i, false, clazz.getClassLoader());
if(syntheticClass.isSynthetic()) {
for(Field declaredField : syntheticClass.getDeclaredFields()) {
if(Modifier.isStatic(declaredField.getModifiers())
&& declaredField.getType()==int[].class
&& declaredField.getName().startsWith("$SwitchMap$")) {
metaObjectData.switchTableFields.add(declaredField);
}
}
}
} catch (Throwable e1) {
break;
}
}
TreeSet declaredFields = new TreeSet<>((m1, m2)->{
return m1.getName().compareTo(m2.getName());
});
declaredFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
signalLoop: for (Field declaredField : declaredFields) {
Class> fieldType = declaredField.getType();
if(declaredField.isSynthetic()
&& Modifier.isStatic(declaredField.getModifiers())
&& Modifier.isPrivate(declaredField.getModifiers())
&& fieldType==int[].class
&& declaredField.getName().startsWith("$SWITCH_TABLE$")) {
metaObjectData.switchTableFields.add(declaredField);
}
if(isQObjectSignalType(fieldType) && !declaredField.isAnnotationPresent(QtUninvokable.class)) {
if (!Modifier.isStatic(declaredField.getModifiers())) {
if(!isQObject && fieldType.getEnclosingClass() == QObject.class)
throw new QSignalDeclarationException(String.format("Declaration error at signal %1$s.%2$s: do not use QObject signals within non-QObjects.", clazz.getSimpleName(), declaredField.getName()));
// If we can't convert all the types we don't list the signal
List> emitParameterTypes = new ArrayList<>();
List signalTypes = new ArrayList<>(SignalUtility.resolveSignal(declaredField));
List cppTypes = new ArrayList<>();
List signalParameterInfos = new ArrayList<>();
for (int j = 0; j < signalTypes.size(); j++) {
emitParameterTypes.add(Object.class);
SignalUtility.SignalParameterType signalType = signalTypes.get(j);
QtMetaType metaTypeDecl = signalType.annotatedType!=null ? signalType.annotatedType.getAnnotation(QtMetaType.class) : null;
int metaTypeId = 0;
String typeName;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(signalType.isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(signalType.isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else{
typeName = internalTypeNameOfClass(signalType.type, signalType.genericType);
if(signalType.isPointer) {
if(!typeName.isEmpty() && !typeName.endsWith("*")) {
typeName += "*";
}
}
if(signalType.isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.isEmpty() && !typeName.endsWith("&")) {
typeName += "&";
}
}
}
QMetaType.Type type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = findMetaType(typeName);
QMetaType metaType = new QMetaType(metaTypeId);
if(metaTypeId==QMetaType.Type.UnknownType.value()
|| !(signalType.genericType instanceof Class
|| metaType.name().toString().equals(typeName))
|| metaType.javaType()!=signalType.type) {
metaTypeId = registerMetaType(signalType.type, signalType.genericType, null, signalType.isPointer, signalType.isReference);
metaType = new QMetaType(metaTypeId);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = metaType.name().toString();
else
continue signalLoop;
}
cppTypes.add(typeName);
signalParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
signalParameterInfos.add(new ParameterInfo(type));
}
}
SignalUtility.EmitMethodInfo emitMethodInfo = findEmitMethodInfo(fieldType, emitParameterTypes);
String methodSignature = String.format("%1$s(%2$s)", declaredField.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature) && emitMethodInfo!=null && emitMethodInfo.methodId!=0) {
if (!Modifier.isFinal(declaredField.getModifiers())) {
if(!Boolean.getBoolean("qtjambi.allow-nonfinal-signals") && !Boolean.getBoolean("io.qt.allow-nonfinal-signals")) {
java.util.logging.Logger.getLogger("io.qt.internal").severe(String.format("Missing modifier 'final' at signal %1$s.%2$s. Specify JVM argument -Dqtjambi.allow-nonfinal-signals=true to disable this error.", clazz.getSimpleName(), declaredField.getName()));
throw new QSignalDeclarationException(String.format("Missing modifier 'final' at signal %1$s.%2$s.", clazz.getSimpleName(), declaredField.getName()));
}
}
// Rules for resetters:
// 1. Zero or one argument
if(signalTypes.size() <= 1){
PropertyAnnotation notify = PropertyAnnotation.notifyAnnotation(declaredField);
if (notify != null) {
for(String name : notify.name().split(",")) {
name = name.trim();
if(!name.isEmpty())
propertyNotifies.put(name, declaredField);
}
}
}
addedMethodSignatures.add(methodSignature);
signalIsClone.add(Boolean.FALSE);
allSignalParameterInfos.add(new ArrayList<>(signalParameterInfos));
metaObjectData.signalInfos.add(new MetaObjectData.SignalInfo(declaredField, new ArrayList<>(signalTypes), fieldType, new int[signalTypes.size()], emitMethodInfo.methodId));
signals.put(declaredField.getName(), declaredField);
Runnable addDefaultSignal = ()->{
signalTypes.remove(signalTypes.size()-1);
signalParameterInfos.remove(signalParameterInfos.size()-1);
cppTypes.remove(cppTypes.size()-1);
emitParameterTypes.remove(emitParameterTypes.size()-1);
SignalUtility.EmitMethodInfo _emitMethodInfo = findEmitMethodInfo(fieldType, emitParameterTypes);
String _methodSignature = String.format("%1$s(%2$s)", declaredField.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(_methodSignature) && _emitMethodInfo!=null && _emitMethodInfo.methodId!=0) {
addedMethodSignatures.add(_methodSignature);
signalIsClone.add(Boolean.TRUE);
allSignalParameterInfos.add(new ArrayList<>(signalParameterInfos));
metaObjectData.signalInfos.add(new MetaObjectData.SignalInfo(declaredField, new ArrayList<>(signalTypes), fieldType, new int[signalTypes.size()], _emitMethodInfo.methodId));
}
};
switch(signalTypes.size()) {
case 9:
if(QMetaObject.Emitable8.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 8:
if(QMetaObject.Emitable7.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 7:
if(QMetaObject.Emitable6.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 6:
if(QMetaObject.Emitable5.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 5:
if(QMetaObject.Emitable4.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 4:
if(QMetaObject.Emitable3.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 3:
if(QMetaObject.Emitable2.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 2:
if(QMetaObject.Emitable1.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
case 1:
if(QMetaObject.Emitable0.class.isAssignableFrom(fieldType)) {
addDefaultSignal.run();
}else break;
}
}
}else {
throw new QSignalDeclarationException(String.format("Modifier 'static' not allowed for signal %1$s.%2$s. Use QStaticMemberSignals instead to declare a static signal.", clazz.getSimpleName(), declaredField.getName()));
}
}else if(isQObject && SignalUtility.AbstractMultiSignal.class.isAssignableFrom(fieldType) && QObject.class!=fieldType.getEnclosingClass()) {
if(Modifier.isStatic(declaredField.getModifiers()))
throw new QSignalDeclarationException(String.format("Modifier 'static' not allowed for signal %1$s.%2$s. Use QStaticMemberSignals instead to declare a static signal.", clazz.getSimpleName(), declaredField.getName()));
if(declaredField.getDeclaringClass()!=fieldType.getEnclosingClass())
throw new QSignalDeclarationException(String.format("Declaration error at signal %1$s.%2$s: Multi signal class has to be declared in the class using it.", clazz.getSimpleName(), declaredField.getName()));
if(!Modifier.isFinal(fieldType.getModifiers()))
throw new QSignalDeclarationException(String.format("Missing modifier 'final' at signal class %1$s.", fieldType.getTypeName()));
if (!Modifier.isFinal(declaredField.getModifiers()))
throw new QSignalDeclarationException(String.format("Missing modifier 'final' at signal %1$s.%2$s.", clazz.getSimpleName(), declaredField.getName()));
Map>,SignalUtility.EmitMethodInfo> emitMethods = SignalUtility.findEmitMethods(fieldType);
if(emitMethods.keySet().isEmpty())
throw new QSignalDeclarationException(String.format("Missing modifier emit methods at signal class %1$s.", fieldType.getTypeName()));
for (SignalUtility.EmitMethodInfo emitMethodInfo : emitMethods.values()) {
if(emitMethodInfo.methodId==0)
continue;
List signalTypes = emitMethodInfo.parameterTypes;
List cppTypes = new ArrayList<>();
List signalParameterInfos = new ArrayList<>();
List> signalClassTypes = new ArrayList<>();
for (int j = 0; j < signalTypes.size(); j++) {
SignalUtility.SignalParameterType signalType = signalTypes.get(j);
signalClassTypes.add(signalType.type);
QtMetaType metaTypeDecl = signalType.annotatedType==null ? null : signalType.annotatedType.getAnnotation(QtMetaType.class);
int metaTypeId = 0;
String typeName;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
metaTypeId = registerRefMetaType(metaTypeId, signalType.isPointer, signalType.isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(signalType.isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(signalType.isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else{
typeName = internalTypeNameOfClass(signalType.type, signalType.genericType);
if(signalType.isPointer) {
if(!typeName.isEmpty() && !typeName.endsWith("*")) {
typeName += "*";
}
}
if(signalType.isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.isEmpty() && !typeName.endsWith("&")) {
typeName += "&";
}
}
}
QMetaType.Type type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = findMetaType(typeName);
QMetaType metaType = new QMetaType(metaTypeId);
if(metaTypeId==QMetaType.Type.UnknownType.value()
|| !(signalType.genericType instanceof Class
|| metaType.name().toString().equals(typeName))
|| metaType.javaType()!=signalType.type) {
metaTypeId = registerMetaType(signalType.type, signalType.genericType, null, signalType.isPointer, signalType.isReference);
metaType = new QMetaType(metaTypeId);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = metaType.name().toString();
else
continue signalLoop;
}
cppTypes.add(typeName);
signalParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
signalParameterInfos.add(new ParameterInfo(type));
}
}
String methodSignature = String.format("%1$s(%2$s)", declaredField.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature)) {
addedMethodSignatures.add(methodSignature);
signalIsClone.add(Boolean.FALSE);
allSignalParameterInfos.add(new ArrayList<>(signalParameterInfos));
Class> _signalClass;
SignalUtility.SignalClasses signalClasses = SignalUtility.signalClasses(QObject.class);
if(signalClasses==null)
throw new QSignalInitializationException("Unable to resolve multi signal.");
if(Modifier.isPublic(emitMethodInfo.method.getModifiers())) {
_signalClass = signalClasses.getPublicSignal(emitMethodInfo.parameterTypes.size());
}else {
_signalClass = signalClasses.getPrivateSignal(emitMethodInfo.parameterTypes.size());
}
metaObjectData.signalInfos.add(new MetaObjectData.SignalInfo(declaredField, new ArrayList<>(signalTypes), _signalClass, new int[signalTypes.size()], emitMethodInfo.methodId));
signals.put(declaredField.getName(), declaredField);
}
}
}else{
PropertyAnnotation member = PropertyAnnotation.memberAnnotation(declaredField);
if(member!=null) {
if(member.enabled()) {
String property = member.name();
if(isQObject && isValidQProperty(declaredField)) {
if (!Modifier.isFinal(declaredField.getModifiers())) {
if(!Boolean.getBoolean("qtjambi.allow-nonfinal-qproperties") && !Boolean.getBoolean("io.qt.allow-nonfinal-qproperties")) {
java.util.logging.Logger.getLogger("io.qt.internal").severe(String.format("Missing modifier 'final' at property field %1$s.%2$s. Specify JVM argument -Dqtjambi.allow-nonfinal-qproperties=true to disable this error.", declaredField.getDeclaringClass().getSimpleName(), declaredField.getName()));
throw new QPropertyDeclarationException(String.format("Missing modifier 'final' at property field %1$s.%2$s.", clazz.getSimpleName(), declaredField.getName()));
}
}
propertyQPropertyFields.put(property, declaredField);
}else {
propertyMembers.put(property, declaredField);
}
propertyDesignableResolvers.put(property, isDesignable(declaredField, clazz));
propertyScriptableResolvers.put(property, isScriptable(declaredField, clazz));
propertyEditableResolvers.put(property, isEditable(declaredField, clazz));
propertyStoredResolvers.put(property, isStored(declaredField, clazz));
propertyUserResolvers.put(property, isUser(declaredField, clazz));
propertyRequiredResolvers.put(property, isRequired(declaredField));
propertyConstantResolvers.put(property, isConstant(declaredField));
}
}else if(isQObject && isValidQProperty(declaredField)) {
if (!Modifier.isFinal(declaredField.getModifiers())) {
if(!Boolean.getBoolean("qtjambi.allow-nonfinal-qproperties") && !Boolean.getBoolean("io.qt.allow-nonfinal-qproperties")) {
java.util.logging.Logger.getLogger("io.qt.internal").severe(String.format("Missing modifier 'final' at property field %1$s.%2$s. Specify JVM argument -Dqtjambi.allow-nonfinal-qproperties=true to disable this error.", declaredField.getDeclaringClass().getSimpleName(), declaredField.getName()));
throw new QPropertyDeclarationException(String.format("Missing modifier 'final' at property field %1$s.%2$s.", clazz.getSimpleName(), declaredField.getName()));
}
}
String property = declaredField.getName();
propertyQPropertyFields.put(property, declaredField);
propertyDesignableResolvers.put(property, isDesignable(declaredField, clazz));
propertyScriptableResolvers.put(property, isScriptable(declaredField, clazz));
propertyEditableResolvers.put(property, isEditable(declaredField, clazz));
propertyStoredResolvers.put(property, isStored(declaredField, clazz));
propertyUserResolvers.put(property, isUser(declaredField, clazz));
propertyRequiredResolvers.put(property, isRequired(declaredField));
propertyConstantResolvers.put(property, isConstant(declaredField));
}else if((isQObject || isGadget) && Modifier.isPublic(declaredField.getModifiers())) {
String property = declaredField.getName();
if(!(Modifier.isStatic(declaredField.getModifiers()) && property.equals("staticMetaObject"))) {
propertyMembers.put(property, declaredField);
propertyDesignableResolvers.put(property, isDesignable(declaredField, clazz));
propertyScriptableResolvers.put(property, isScriptable(declaredField, clazz));
propertyEditableResolvers.put(property, isEditable(declaredField, clazz));
propertyStoredResolvers.put(property, isStored(declaredField, clazz));
propertyUserResolvers.put(property, isUser(declaredField, clazz));
propertyRequiredResolvers.put(property, isRequired(declaredField));
propertyConstantResolvers.put(property, isConstant(declaredField, Modifier.isFinal(declaredField.getModifiers())));
}
}
}
}
}
List> allConstructorParameterInfos = new ArrayList<>();
{
TreeSet> declaredConstructors = new TreeSet<>((m1, m2)->{
return m1.toGenericString().compareTo(m2.toGenericString());
});
declaredConstructors.addAll(Arrays.asList(clazz.getDeclaredConstructors()));
cloop: for(Constructor> constructor : declaredConstructors){
if(!constructor.isSynthetic() && constructor.isAnnotationPresent(QtInvokable.class)) {
Class>[] parameterTypes = constructor.getParameterTypes();
for (Class> parameterType : parameterTypes) {
if(parameterType==Classes.QPrivateConstructor()
|| parameterType==Classes.QDeclarativeConstructor()) {
continue cloop;
}
}
List cppTypes = new ArrayList<>();
List constructorParameterInfos = new ArrayList<>();
Type[] genericParameterTypes = constructor.getGenericParameterTypes();
AnnotatedElement[] annotatedParameterTypes = null;
if(ClassAnalyzerUtility.useAnnotatedType) {
annotatedParameterTypes = constructor.getAnnotatedParameterTypes();
}
for (int j = 0; j < parameterTypes.length; j++) {
boolean isPointer = false;
boolean isReference = false;
if(annotatedParameterTypes!=null && annotatedParameterTypes[j]!=null) {
if(annotatedParameterTypes[j].isAnnotationPresent(QtPointerType.class)) {
isPointer = true;
}
QtReferenceType referenceType = annotatedParameterTypes[j].getAnnotation(QtReferenceType.class);
if(referenceType!=null && !referenceType.isConst()) {
isReference = true;
}
}
String typeName;
QtMetaType metaTypeDecl = annotatedParameterTypes==null || annotatedParameterTypes[j]==null ? null : annotatedParameterTypes[j].getAnnotation(QtMetaType.class);
int metaTypeId = 0;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else {
typeName = internalTypeNameOfClass(parameterTypes[j], genericParameterTypes[j]);
if(isPointer) {
if(!typeName.isEmpty() && !typeName.endsWith("*")) {
typeName += "*";
}
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.isEmpty() && !typeName.endsWith("&")) {
typeName += "&";
}
}
}
QMetaType.Type type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = findMetaType(typeName);
QMetaType metaType = new QMetaType(metaTypeId);
if(metaTypeId==QMetaType.Type.UnknownType.value()
|| !(genericParameterTypes[j] instanceof Class
|| new QMetaType(metaTypeId).name().toString().equals(typeName))
|| metaType.javaType()!=parameterTypes[j]) {
metaTypeId = registerMetaType(parameterTypes[j],
genericParameterTypes[j],
annotatedParameterTypes!=null ? annotatedParameterTypes[j] : null,
isPointer,
isReference);
metaType = new QMetaType(metaTypeId);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = metaType.name().toString();
else continue cloop;
}
cppTypes.add(typeName);
constructorParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
constructorParameterInfos.add(new ParameterInfo(type));
}
}
String name = constructor.getName();
String methodSignature = String.format("%1$s(%2$s)", name, String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature)) {
addedMethodSignatures.add(methodSignature);
allConstructorParameterInfos.add(constructorParameterInfos);
metaObjectData.constructors.add(constructor);
metaObjectData.constructorMetaTypes.add(new MetaObjectData.MetaTypeInfo[parameterTypes.length+1]);
metaObjectData.hasStaticMembers = true;
}
}
}
}
List> allMethodParameterInfos = new ArrayList<>();
List possibleBindables = Collections.emptyList();
TreeSet declaredMethods = new TreeSet<>((m1, m2)->{
return m1.toGenericString().compareTo(m2.toGenericString());
});
declaredMethods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
List> possibleReaders = Collections.emptyList();
Set usedGetters = new HashSet<>();
for (Method declaredMethod : declaredMethods) {
if(declaredMethod.isSynthetic()
|| declaredMethod.isBridge()) {
continue;
}
final String declaredMethodName = declaredMethod.getName();
// Rules for readers:
// 1. Zero arguments
// 2. Return something other than void
// 3. We can convert the type
PropertyAnnotation reader = PropertyAnnotation.readerAnnotation(declaredMethod);
{
if (
(reader != null && reader.enabled())
&& isValidGetter(declaredMethod)) {
String name = reader.name();
// If the return type of the property reader is not registered, then
// we need to register the owner class in the meta object (in which case
// it has to be a QObject)
Class> returnType = declaredMethod.getReturnType();
if ( (QFlags.class.isAssignableFrom(returnType) || Enum.class.isAssignableFrom(returnType))
&& !isEnumAllowedForProperty(returnType) ) {
int type = QMetaType.qRegisterMetaType(returnType);
if(type==QMetaType.Type.UnknownType.value()) {
System.err.println("Problem in property '" + name + "' in '" + clazz.getName()
+ "' with return type '"+returnType.getName()
+"': Unable to register meta type.");
continue;
}
}
Field signalField = signals.get(name);
if(signalField!=null && SignalUtility.AbstractSignal.class.isAssignableFrom(returnType))
continue;
propertyReaders.put(name, declaredMethod);
usedGetters.add(declaredMethod);
propertyDesignableResolvers.put(name, isDesignable(declaredMethod, clazz));
propertyScriptableResolvers.put(name, isScriptable(declaredMethod, clazz));
propertyEditableResolvers.put(name, isEditable(declaredMethod, clazz));
propertyStoredResolvers.put(name, isStored(declaredMethod, clazz));
propertyUserResolvers.put(name, isUser(declaredMethod, clazz));
propertyRequiredResolvers.put(name, isRequired(declaredMethod));
propertyConstantResolvers.put(name, isConstant(declaredMethod));
propertyFinalResolvers.put(name, isFinal(declaredMethod));
}
}
// Rules for writers:
// 1. Takes exactly one argument
// 2. Return void
// 3. We can convert the type
PropertyAnnotation writer = PropertyAnnotation.writerAnnotation(declaredMethod);
{
if ( writer != null
&& writer.enabled()
&& isValidSetter(declaredMethod)) {
propertyWriters.computeIfAbsent(writer.name(), arrayListFactory()).add(declaredMethod);
}
}
// Check naming convention by looking for setXxx patterns, but only if it hasn't already been
// annotated as a writer
if ((isQObject || isGadget)
&& writer == null
&& reader == null // reader can't be a writer, cause the signature doesn't match, just an optimization
) {
if(declaredMethodName.startsWith("set")
&& declaredMethodName.length() > 3
&& Character.isUpperCase(declaredMethodName.charAt(3))
&& isValidSetter(declaredMethod)) {
Class> paramType = declaredMethod.getParameterTypes()[0];
String propertyName = Character.toLowerCase(declaredMethodName.charAt(3))
+ declaredMethodName.substring(4);
if (!propertyReaders.containsKey(propertyName)) {
// We need a reader as well, and the reader must not be annotated as disabled
// The reader can be called 'xxx', 'getXxx', 'isXxx' or 'hasXxx'
// (just booleans for the last two)
Method readerMethod = findPropertyReader(getDeclaredMethod(clazz, propertyName), propertyName, paramType);
if (readerMethod == null)
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "get" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "is" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "has" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod != null) { // yay
reader = PropertyAnnotation.readerAnnotation(readerMethod);
if (reader == null) {
usedGetters.add(readerMethod);
propertyReaders.put(propertyName, readerMethod);
propertyWriters.computeIfAbsent(propertyName, arrayListFactory()).add(declaredMethod);
propertyDesignableResolvers.put(propertyName, isDesignable(readerMethod, clazz));
propertyScriptableResolvers.put(propertyName, isScriptable(readerMethod, clazz));
propertyUserResolvers.put(propertyName, isUser(readerMethod, clazz));
propertyRequiredResolvers.put(propertyName, isRequired(readerMethod));
}
}
}
}else if(isValidGetter(declaredMethod)){
int offset = 3;
if(( declaredMethodName.startsWith("get")
|| (isBoolean(declaredMethod.getReturnType()) && declaredMethodName.startsWith("has"))
|| (isBoolean(declaredMethod.getReturnType()) && (--offset==2) && declaredMethodName.startsWith("is"))
) && declaredMethodName.length() > offset
&& Character.isUpperCase(declaredMethodName.charAt(offset))) {
String propertyName = Character.toLowerCase(declaredMethodName.charAt(offset))
+ declaredMethodName.substring(offset+1);
if(possibleReaders.isEmpty())
possibleReaders = new ArrayList<>();
possibleReaders.add(new QPair<>(propertyName, declaredMethod));
}
}
}
// Rules for notifys:
// 1. No arguments
// 2. Return void
{
PropertyAnnotation resetter = PropertyAnnotation.resetterAnnotation(declaredMethod);
if (resetter != null
&& declaredMethod.getParameterCount() == 0
&& declaredMethod.getReturnType() == void.class) {
propertyResetters.put(resetter.name(), declaredMethod);
}
}
if(isValidBindable(declaredMethod)) {
PropertyAnnotation bindables = PropertyAnnotation.bindableAnnotation(declaredMethod);
if (bindables != null) {
propertyBindables.put(bindables.name(), declaredMethod);
}else{
if(possibleBindables.isEmpty())
possibleBindables = new ArrayList<>();
possibleBindables.add(declaredMethod);
}
}
}
for(QPair pair : possibleReaders) {
if (!propertyReaders.containsKey(pair.first) && !usedGetters.contains(pair.second)) {
Field signalField = signals.get(pair.first);
if(signalField!=null && SignalUtility.AbstractSignal.class.isAssignableFrom(pair.second.getReturnType()))
continue;
propertyReaders.put(pair.first, pair.second);
propertyDesignableResolvers.put(pair.first, isDesignable(pair.second, clazz));
propertyScriptableResolvers.put(pair.first, isScriptable(pair.second, clazz));
propertyUserResolvers.put(pair.first, isUser(pair.second, clazz));
propertyRequiredResolvers.put(pair.first, isRequired(pair.second));
}
}
for(Method possibleBindable : possibleBindables) {
String propertyName = possibleBindable.getName();
if(propertyName.startsWith("bindable") && propertyName.length() > 8) {
propertyName = PropertyAnnotation.removeAndLowercaseFirst(propertyName, 8);
if (propertyReaders.containsKey(propertyName) || propertyWriters.containsKey(propertyName)) {
propertyBindables.put(propertyName, possibleBindable);
}else {
QPropertyTypeInfo typeInfo = getQPropertyTypeInfo(possibleBindable);
if(typeInfo!=null) {
Class> paramType = typeInfo.propertyType;
Method readerMethod = findPropertyReader(getDeclaredMethod(clazz, propertyName), propertyName, paramType);
if (readerMethod == null)
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "get" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "is" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "has" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod != null) { // yay
propertyReaders.put(propertyName, readerMethod);
propertyBindables.put(propertyName, possibleBindable);
propertyDesignableResolvers.put(propertyName, isDesignable(readerMethod, clazz));
propertyScriptableResolvers.put(propertyName, isScriptable(readerMethod, clazz));
propertyUserResolvers.put(propertyName, isUser(readerMethod, clazz));
propertyRequiredResolvers.put(propertyName, isRequired(readerMethod));
}else {
Method writerMethod = findPropertyWriter(getDeclaredMethod(clazz, "set"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1), paramType), propertyName, paramType);
if(writerMethod != null) {
PropertyAnnotation writer = PropertyAnnotation.writerAnnotation(writerMethod);
if (writer == null) {
propertyWriters.computeIfAbsent(propertyName, arrayListFactory()).add(writerMethod);
propertyDesignableResolvers.put(propertyName, isDesignable(writerMethod, clazz));
propertyScriptableResolvers.put(propertyName, isScriptable(writerMethod, clazz));
propertyUserResolvers.put(propertyName, isUser(writerMethod, clazz));
propertyRequiredResolvers.put(propertyName, isRequired(writerMethod));
}
}
}
}
}
}
}
for(MetaObjectData.SignalInfo signalInfo : metaObjectData.signalInfos) {
if(signalInfo.field.getName().endsWith("Changed")) {
String propertyName = signalInfo.field.getName();
propertyName = propertyName.substring(0, propertyName.length()-7);
if (!propertyReaders.containsKey(propertyName)) {
Class> paramType = signalInfo.signalTypes.size()==1 ? signalInfo.signalTypes.get(0).type : null;
Method readerMethod = findPropertyReader(getDeclaredMethod(clazz, propertyName), propertyName, paramType);
if (readerMethod == null)
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "get" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "is" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod == null && isBoolean(paramType))
readerMethod = findPropertyReader(getDeclaredMethod(clazz, "has" + capitalizeFirst(propertyName)), propertyName, paramType);
if (readerMethod != null) { // yay
propertyReaders.put(propertyName, readerMethod);
propertyNotifies.put(propertyName, signalInfo.field);
propertyDesignableResolvers.put(propertyName, isDesignable(readerMethod, clazz));
propertyScriptableResolvers.put(propertyName, isScriptable(readerMethod, clazz));
propertyUserResolvers.put(propertyName, isUser(readerMethod, clazz));
propertyRequiredResolvers.put(propertyName, isRequired(readerMethod));
}else {
Method writerMethod;
writerMethod = findPropertyWriter(getDeclaredMethod(clazz, "set"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1), paramType), propertyName, paramType);
if(writerMethod != null) {
PropertyAnnotation writer = PropertyAnnotation.writerAnnotation(writerMethod);
if (writer == null) {
propertyWriters.computeIfAbsent(propertyName, arrayListFactory()).add(writerMethod);
propertyDesignableResolvers.put(propertyName, isDesignable(writerMethod, clazz));
propertyScriptableResolvers.put(propertyName, isScriptable(writerMethod, clazz));
propertyUserResolvers.put(propertyName, isUser(writerMethod, clazz));
propertyRequiredResolvers.put(propertyName, isRequired(writerMethod));
}
}
}
}
}
}
{
TreeMap _propertyQPropertyFields = new TreeMap<>(propertyQPropertyFields);
propertyQPropertyFields.clear();
for(Map.Entry entry : _propertyQPropertyFields.entrySet()) {
String name = entry.getKey();
if(name.endsWith("Prop")) {
name = name.substring(0, name.length()-4);
}else if(name.endsWith("Property")) {
name = name.substring(0, name.length()-8);
}
PropertyAnnotation member;
if(!propertyReaders.containsKey(entry.getKey())
&& !propertyReaders.containsKey(name)
&& !Modifier.isStatic(entry.getValue().getModifiers())
&& Modifier.isFinal(entry.getValue().getModifiers())
&& (Modifier.isPublic(entry.getValue().getModifiers())
|| ((member = PropertyAnnotation.memberAnnotation(entry.getValue()))!=null && member.enabled()))) {
propertyReaders.put(name, null);
propertyQPropertyFields.put(name, entry.getValue());
}
}
}
for(String prop : propertyMembers.keySet()) {
if(!propertyReaders.containsKey(prop)) {
propertyReaders.put(prop, null);
}
}
for (Method declaredMethod : declaredMethods) {
if(declaredMethod.isSynthetic()
|| declaredMethod.isBridge()) {
continue;
}
QtInvokable invokable = declaredMethod.getAnnotation(QtInvokable.class);
if (
(
(isQObject || isGadget)
&& !declaredMethod.isAnnotationPresent(QtUninvokable.class)
&& !Modifier.isStatic(declaredMethod.getModifiers())
&& (declaredMethod.getReturnType()==void.class || Modifier.isPublic(declaredMethod.getModifiers()))
&& !(declaredMethod.getParameterCount()==0 && "clone".equals(declaredMethod.getName()))
&& !isOverriding(declaredMethod, clazz)
) || (
invokable!=null
&& invokable.value()
)
) {
List methodParameterInfos = new ArrayList<>();
boolean isPointer = false;
boolean isReference = false;
if(ClassAnalyzerUtility.useAnnotatedType
&& (declaredMethod.getAnnotatedReturnType().isAnnotationPresent(QtPointerType.class)
|| declaredMethod.isAnnotationPresent(QtPointerType.class))) {
isPointer = true;
}
QtReferenceType referenceType = null;
if(ClassAnalyzerUtility.useAnnotatedType) {
if(declaredMethod.getAnnotatedReturnType()!=null)
referenceType = declaredMethod.getAnnotatedReturnType().getAnnotation(QtReferenceType.class);
}
if(referenceType==null)
referenceType = declaredMethod.getAnnotation(QtReferenceType.class);
if(referenceType!=null && !referenceType.isConst()) {
isReference = true;
}
QtMetaType metaTypeDecl = null;
if(ClassAnalyzerUtility.useAnnotatedType) {
if(declaredMethod.getAnnotatedReturnType()!=null)
metaTypeDecl = declaredMethod.getAnnotatedReturnType().getAnnotation(QtMetaType.class);
}
int metaTypeId = 0;
String typeName;
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else {
typeName = internalTypeNameOfClass(declaredMethod.getReturnType(), declaredMethod.getGenericReturnType());
if(isPointer) {
if(!typeName.isEmpty() && !typeName.endsWith("*")) {
typeName += "*";
}
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.isEmpty() && !typeName.endsWith("&")) {
typeName += "&";
}
}
}
QMetaType.Type type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = findMetaType(typeName);
QMetaType metaType = new QMetaType(metaTypeId);
if(metaTypeId==QMetaType.Type.UnknownType.value()
|| !(declaredMethod.getGenericReturnType() instanceof Class
|| metaType.name().toString().equals(typeName))
|| metaType.javaType()!=declaredMethod.getReturnType()) {
AnnotatedElement ae = null;
if(ClassAnalyzerUtility.useAnnotatedType)
ae = declaredMethod.getAnnotatedReturnType();
metaTypeId = registerMetaType(
declaredMethod.getReturnType(),
declaredMethod.getGenericReturnType(),
ae,
isPointer,
isReference);
metaType = new QMetaType(metaTypeId);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = metaType.name().toString();
}
methodParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
methodParameterInfos.add(new ParameterInfo(type));
}
List cppTypes = new ArrayList<>();
Class>[] parameterTypes = declaredMethod.getParameterTypes();
Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();
AnnotatedElement[] annotatedParameterTypes = null;
if(ClassAnalyzerUtility.useAnnotatedType) {
annotatedParameterTypes = declaredMethod.getAnnotatedParameterTypes();
}
for (int j = 0; j < parameterTypes.length; j++) {
metaTypeId = 0;
isPointer = false;
isReference = false;
if(annotatedParameterTypes!=null && annotatedParameterTypes[j]!=null) {
if(annotatedParameterTypes[j].isAnnotationPresent(QtPointerType.class)) {
isPointer = true;
}
referenceType = annotatedParameterTypes[j].getAnnotation(QtReferenceType.class);
if(referenceType!=null && !referenceType.isConst()) {
isReference = true;
}
metaTypeDecl = annotatedParameterTypes[j].getAnnotation(QtMetaType.class);
}
if(metaTypeDecl!=null) {
if(metaTypeDecl.id()!=0) {
metaTypeId = metaTypeDecl.id();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else if(metaTypeDecl.type()!=QMetaType.Type.UnknownType){
metaTypeId = metaTypeDecl.type().value();
if(isPointer || isReference) {
metaTypeId = registerRefMetaType(metaTypeId, isPointer, isReference);
}
typeName = new QMetaType(metaTypeId).name().toString();
}else {
if(metaTypeDecl.name().isEmpty())
throw new IllegalArgumentException("Incomplete @QtMetaType declaration. Either use type, id or name to specify meta type.");
typeName = metaTypeDecl.name();
if(isPointer && !typeName.endsWith("*")) {
typeName += "*";
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.endsWith("&")) {
typeName += "&";
}
}
}
}else {
typeName = internalTypeNameOfClass(parameterTypes[j], genericParameterTypes[j]);
if(isPointer) {
if(!typeName.isEmpty() && !typeName.endsWith("*")) {
typeName += "*";
}
}
if(isReference) {
if(typeName.endsWith("*")) {
typeName = typeName.substring(0, typeName.length()-2);
}
if(!typeName.isEmpty() && !typeName.endsWith("&")) {
typeName += "&";
}
}
}
type = metaType(typeName);
if(type==QMetaType.Type.UnknownType || type==QMetaType.Type.User){
if(metaTypeId==QMetaType.Type.UnknownType.value()) {
metaTypeId = findMetaType(typeName);
QMetaType metaType = new QMetaType(metaTypeId);
if(metaTypeId==QMetaType.Type.UnknownType.value()
|| !(genericParameterTypes[j] instanceof Class
|| metaType.name().toString().equals(typeName))
|| metaType.javaType()!=parameterTypes[j]) {
metaTypeId = registerMetaType(parameterTypes[j],
genericParameterTypes[j],
annotatedParameterTypes==null ? null : annotatedParameterTypes[j],
isPointer,
isReference);
metaType = new QMetaType(metaTypeId);
}
if(metaTypeId!=QMetaType.Type.UnknownType.value())
typeName = metaType.name().toString();
}
cppTypes.add(typeName);
methodParameterInfos.add(new ParameterInfo(metaTypeId, typeName));
}else{
cppTypes.add(new QMetaType(type).name().toString());
methodParameterInfos.add(new ParameterInfo(type));
}
}
String methodSignature = String.format("%1$s(%2$s)", declaredMethod.getName(), String.join(", ", cppTypes));
if(!addedMethodSignatures.contains(methodSignature)) {
allMethodParameterInfos.add(methodParameterInfos);
metaObjectData.methods.add(declaredMethod);
if(Modifier.isStatic(declaredMethod.getModifiers())){
methodFlags.put(declaredMethod, MethodFlags.MethodMethod);
metaObjectData.hasStaticMembers = true;
}else{
if(!isQObject) {
// we need to make sure that static_metacall is set
metaObjectData.hasStaticMembers = true;
methodFlags.put(declaredMethod, MethodFlags.MethodMethod);
}else {
methodFlags.put(declaredMethod, MethodFlags.MethodSlot);
}
}
metaObjectData.methodMetaTypes.add(new MetaObjectData.MetaTypeInfo[declaredMethod.getParameterCount()+1]);
}
}
}
for(String property : propertyReaders.keySet()) {
if(propertyNotifies.get(property)==null) {
for(MetaObjectData.SignalInfo signalInfo : metaObjectData.signalInfos) {
if(signalInfo.field.getName().equals(property+"Changed")) {
if(signalInfo.signalTypes.isEmpty()) {
propertyNotifies.put(property, signalInfo.field);
}else {
Field propertyField;
Method reader;
if((reader = propertyReaders.get(property))!=null) {
if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(reader.getReturnType()))) {
propertyNotifies.put(property, signalInfo.field);
}
}else if((propertyField = propertyMembers.get(property))!=null) {
if(isValidQProperty(propertyField)) {
MetaObjectUtility.QPropertyTypeInfo pinfo = getQPropertyTypeInfo(propertyField);
if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(pinfo.propertyType))) {
propertyNotifies.put(property, signalInfo.field);
}
}else if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(propertyField.getType()))) {
propertyNotifies.put(property, signalInfo.field);
}
}else if((propertyField = propertyQPropertyFields.get(property))!=null) {
MetaObjectUtility.QPropertyTypeInfo pinfo = getQPropertyTypeInfo(propertyField);
if(signalInfo.signalTypes.get(0).type.isAssignableFrom(getBoxedType(pinfo.propertyType))) {
propertyNotifies.put(property, signalInfo.field);
}
}
}
break;
}
}
}
}
int flagsIndex = 0;
{
// Until 4.7.x QtJambi used revision=1 however due to a change in the way
// 4.7.x works some features of QtJambi stopped working.
// revision 1 = MO_HEADER_LEN=10
// revision 2 (4.5.x) = MO_HEADER_LEN=12 (added: constructorCount, constructorData)
// revision 3 = MO_HEADER_LEN=13 (added: flags)
// revision 4 (4.6.x) = MO_HEADER_LEN=14 (added: signalCount)
// revision 5 (4.7.x) = MO_HEADER_LEN=14 (normalization)
// revision 6 (4.8.x) = MO_HEADER_LEN=14 (added support for qt_static_metacall)
// revision 7 (5.0.x) = MO_HEADER_LEN=14 (Qt5 to break backwards compatibility)
// The format is compatible to share the same encoding code
// then we can change the revision to suit the Qt
/// implementation we are working with.
final int MO_HEADER_LEN = 14; // header size
// revision
metaObjectData.intData.add(revision); intdataComments.add("revision");
// classname
metaObjectData.intData.add(metaObjectData.addStringDataAndReturnIndex(classname)); intdataComments.add("className");
// classinfo
metaObjectData.intData.add(classInfos.size()); intdataComments.add("classInfoCount");
metaObjectData.intData.add(classInfos.isEmpty() ? 0 : MO_HEADER_LEN); intdataComments.add("classInfoData");
// methods
int methodCount = metaObjectData.signalInfos.size() + metaObjectData.methods.size();
metaObjectData.intData.add(methodCount); intdataComments.add("methodCount");
final int METHOD_METADATA_INDEX = metaObjectData.intData.size();
metaObjectData.intData.add(0); intdataComments.add("methodData");
// properties
metaObjectData.intData.add(propertyReaders.size()); intdataComments.add("propertyCount");
final int PROPERTY_METADATA_INDEX = metaObjectData.intData.size();
metaObjectData.intData.add(0); intdataComments.add("propertyData");
// enums/sets
metaObjectData.intData.add(enums.size()); intdataComments.add("enumeratorCount");
final int ENUM_METADATA_INDEX = metaObjectData.intData.size();
metaObjectData.intData.add(0); intdataComments.add("enumeratorData");
// constructors
metaObjectData.intData.add(!metaObjectData.constructors.isEmpty() ? metaObjectData.constructors.size() : 0); intdataComments.add("constructorCount");
final int CONSTRUCTOR_METADATA_INDEX = metaObjectData.intData.size();
metaObjectData.intData.add(0); intdataComments.add("constructorData");
// flags
flagsIndex = metaObjectData.intData.size();
metaObjectData.intData.add(0); intdataComments.add("flags");
// signalCount
metaObjectData.intData.add(metaObjectData.signalInfos.size()); intdataComments.add("signalCount");
//
// Build classinfo array
//
for(Map.Entry entry : classInfos.entrySet()){
// classinfo: key, value
metaObjectData.intData.add(metaObjectData.addStringDataAndReturnIndex(entry.getKey())); intdataComments.add("classinfo: key");
metaObjectData.intData.add(metaObjectData.addStringDataAndReturnIndex(entry.getValue())); intdataComments.add("classinfo: value");
}
HashMap