Böyle bir dersim varsa:
public class Whatever
{
public void aMethod(int aParam);
}
aMethod
adlı bir parametre kullandığını bilmenin herhangi bir yolu var mı aParam
, bu türden int
?
Böyle bir dersim varsa:
public class Whatever
{
public void aMethod(int aParam);
}
aMethod
adlı bir parametre kullandığını bilmenin herhangi bir yolu var mı aParam
, bu türden int
?
Yanıtlar:
Özetlemek:
method.getParameterTypes()
Bir düzenleyici için otomatik tamamlama işlevini yazmak adına (yorumlardan birinde belirttiğiniz gibi) birkaç seçenek vardır:
arg0
, arg1
, arg2
vbintParam
, stringParam
, objectTypeParam
vbJava 8'de şunları yapabilirsiniz:
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
public final class Methods {
public static List<String> getParameterNames(Method method) {
Parameter[] parameters = method.getParameters();
List<String> parameterNames = new ArrayList<>();
for (Parameter parameter : parameters) {
if(!parameter.isNamePresent()) {
throw new IllegalArgumentException("Parameter names are not present!");
}
String parameterName = parameter.getName();
parameterNames.add(parameterName);
}
return parameterNames;
}
private Methods(){}
}
Yani sınıfınız Whatever
için manuel bir test yapabiliriz:
import java.lang.reflect.Method;
public class ManualTest {
public static void main(String[] args) {
Method[] declaredMethods = Whatever.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (declaredMethod.getName().equals("aMethod")) {
System.out.println(Methods.getParameterNames(declaredMethod));
break;
}
}
}
}
hangi yazdırmalısınız [aParam]
sen geçtiyseniz -parameters
Java 8 derleyici argüman.
Maven kullanıcıları için:
<properties>
<!-- PLUGIN VERSIONS -->
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
<!-- OTHER PROPERTIES -->
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<!-- Original answer -->
<compilerArgument>-parameters</compilerArgument>
<!-- Or, if you use the plugin version >= 3.6.2 -->
<parameters>true</parameters>
<testCompilerArgument>-parameters</testCompilerArgument>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
Daha fazla bilgi için aşağıdaki bağlantılara bakın:
Paranamer kütüphanesi aynı sorunu çözmek için oluşturuldu.
Birkaç farklı yolla yöntem adlarını belirlemeye çalışır. Sınıf, hata ayıklama ile derlenmişse, sınıfın bayt kodunu okuyarak bilgileri çıkarabilir.
Diğer bir yol da, derlendikten sonra, ancak bir kavanoz içine yerleştirilmeden önce sınıfın bayt koduna özel bir statik üye enjekte etmesidir. Daha sonra bu bilgiyi çalışma zamanında sınıftan çıkarmak için yansıma kullanır.
https://github.com/paul-hammant/paranamer
Bu kütüphaneyi kullanırken sorun yaşadım ama sonunda onu çalıştırdım. Sorunları bakıcıya bildirmeyi umuyorum.
ParameterNAmesNotFoundException
org.springframework.core.DefaultParameterNameDiscoverer sınıfına bakın
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] params = discoverer.getParameterNames(MathUtils.class.getMethod("isPrime", Integer.class));
Evet.
Kod , resmi parametre adlarını saklama seçeneği açık ( -parametreler seçeneği) ile Java 8 uyumlu derleyici ile derlenmelidir .
Daha sonra bu kod parçacığı çalışmalıdır:
Class<String> clz = String.class;
for (Method m : clz.getDeclaredMethods()) {
System.err.println(m.getName());
for (Parameter p : m.getParameters()) {
System.err.println(" " + p.getName());
}
}
Yöntemi yansıma ile alabilir ve argüman türlerini tespit edebilirsiniz. Http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Method.html#getParameterTypes%28%29 adresini kontrol edin
Ancak, kullanılan argümanın adını söyleyemezsiniz.
Mümkün ve Spring MVC 3 bunu yapıyor, ancak tam olarak nasıl olduğunu görmek için zaman ayırmadım.
Yöntem parametre adlarının URI Şablon değişken adlarıyla eşleştirilmesi, yalnızca kodunuz hata ayıklama etkinken derlenmişse yapılabilir. Hata ayıklamayı etkinleştirmediyseniz, değişken adının çözümlenmiş değerini bir yöntem parametresine bağlamak için @PathVariable ek açıklamasında URI Şablon değişken adını belirtmeniz gerekir. Örneğin:
Alındığı yay belgelerinde
Mümkün olmasa da (diğerlerinin de gösterdiği gibi) siz olabilir parametre adı üzerinde taşımak için bir şerh kullanın ve yansıma olsa o elde ederiz.
En temiz çözüm değil, ama işi hallediyor. Bazı web hizmetleri bunu parametre adlarını korumak için yapar (yani: WS'leri cam balığı ile dağıtmak).
Bakınız java.beans.ConstructorProperties , tam olarak bunu yapmak için tasarlanmış bir ek açıklamadır.
Yani şunları yapabilmelisiniz:
Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }
Ama muhtemelen şöyle bir liste alacaksınız:
["int : arg0"]
Bunun Groovy 2.5+ sürümünde düzeltileceğine inanıyorum
Şu anda cevap şu:
Ayrıca bakınız:
Her yöntem için, o zaman şöyle bir şey:
Whatever.declaredMethods
.findAll { !it.synthetic }
.collect { method ->
println method
method.name + " -> " + method.parameters.collect { "[$it.type : $it.name]" }.join(';')
}
.each {
println it
}
aMethod
. Bir sınıftaki tüm yöntemler için almak istiyorum.
antlr
için parametre isimlerini almak için kullanamaz mıyız ?
@Bozho'nun belirttiği gibi, derleme sırasında hata ayıklama bilgisi dahil edilirse bunu yapmak mümkündür. Burada güzel bir cevap var ...
Bir nesnenin kurucularının (yansıma) parametre adları nasıl alınır? @AdamPaynter tarafından
... ASM kitaplığını kullanarak. Hedefinize nasıl ulaşabileceğinizi gösteren bir örnek oluşturdum.
Öncelikle, bu bağımlılıkları içeren bir pom.xml ile başlayın.
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<version>5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
O zaman bu sınıf istediğinizi yapmalıdır. Sadece statik yöntemi çağırın getParameterNames()
.
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;
public class ArgumentReflection {
/**
* Returns a list containing one parameter name for each argument accepted
* by the given constructor. If the class was compiled with debugging
* symbols, the parameter names will match those provided in the Java source
* code. Otherwise, a generic "arg" parameter name is generated ("arg0" for
* the first argument, "arg1" for the second...).
*
* This method relies on the constructor's class loader to locate the
* bytecode resource that defined its class.
*
* @param theMethod
* @return
* @throws IOException
*/
public static List<String> getParameterNames(Method theMethod) throws IOException {
Class<?> declaringClass = theMethod.getDeclaringClass();
ClassLoader declaringClassLoader = declaringClass.getClassLoader();
Type declaringType = Type.getType(declaringClass);
String constructorDescriptor = Type.getMethodDescriptor(theMethod);
String url = declaringType.getInternalName() + ".class";
InputStream classFileInputStream = declaringClassLoader.getResourceAsStream(url);
if (classFileInputStream == null) {
throw new IllegalArgumentException(
"The constructor's class loader cannot find the bytecode that defined the constructor's class (URL: "
+ url + ")");
}
ClassNode classNode;
try {
classNode = new ClassNode();
ClassReader classReader = new ClassReader(classFileInputStream);
classReader.accept(classNode, 0);
} finally {
classFileInputStream.close();
}
@SuppressWarnings("unchecked")
List<MethodNode> methods = classNode.methods;
for (MethodNode method : methods) {
if (method.name.equals(theMethod.getName()) && method.desc.equals(constructorDescriptor)) {
Type[] argumentTypes = Type.getArgumentTypes(method.desc);
List<String> parameterNames = new ArrayList<String>(argumentTypes.length);
@SuppressWarnings("unchecked")
List<LocalVariableNode> localVariables = method.localVariables;
for (int i = 1; i <= argumentTypes.length; i++) {
// The first local variable actually represents the "this"
// object if the method is not static!
parameterNames.add(localVariables.get(i).name);
}
return parameterNames;
}
}
return null;
}
}
İşte bir birim testi örneği.
public class ArgumentReflectionTest {
@Test
public void shouldExtractTheNamesOfTheParameters3() throws NoSuchMethodException, SecurityException, IOException {
List<String> parameterNames = ArgumentReflection
.getParameterNames(Clazz.class.getMethod("callMe", String.class, String.class));
assertEquals("firstName", parameterNames.get(0));
assertEquals("lastName", parameterNames.get(1));
assertEquals(2, parameterNames.size());
}
public static final class Clazz {
public void callMe(String firstName, String lastName) {
}
}
}
Tam örneği GitHub'da bulabilirsiniz
static
yöntemlerle çalışmaz . Bu, bu durumda ASM tarafından döndürülen argümanların sayısının farklı olmasından kaynaklanır, ancak bu kolayca düzeltilebilecek bir şeydir.Parametre adları yalnızca derleyici için yararlıdır. Derleyici bir sınıf dosyası oluşturduğunda, parametre adları dahil edilmez - bir yöntemin argüman listesi yalnızca argümanlarının sayısı ve türlerinden oluşur. Dolayısıyla, yansıma kullanarak parametre adını almak imkansız olacaktır (sorunuzda etiketlendiği gibi) - hiçbir yerde mevcut değildir.
Ancak, yansıma kullanımı zor bir gereklilik değilse, bu bilgiyi doğrudan kaynak kodundan alabilirsiniz (elinizde olduğunu varsayarak).
Parameter names are only useful to the compiler.
Yanlış. Retrofit kitaplığına bakın. REST API istekleri oluşturmak için dinamik Arayüzler kullanır. Özelliklerinden biri, URL yollarında yer tutucu adlarını tanımlama ve bu yer tutucuları karşılık gelen parametre adlarıyla değiştirme yeteneğidir.
2 sentimi eklemek için; parametre bilgisi, kaynağı derlemek için javac -g kullandığınızda "hata ayıklama için" bir sınıf dosyasında mevcuttur. Ve APT tarafından kullanılabilir, ancak bir ek açıklamaya ihtiyacınız olacak, bu yüzden size faydası yok. (Biri 4-5 yıl önce benzer bir şeyi burada tartıştı: http://forums.java.net/jive/thread.jspa?messageID=13467&tstart=0 )
Genel olarak kısaca, Kaynak dosyalar üzerinde doğrudan çalışmadığınız sürece elde edemezsiniz (APT'nin derleme zamanında yaptığı gibi).