-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Want to support dynamic Class injection base #33206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Rather than asking for a code change, can you please first share the context? What are you trying to do? |
Create a SpringBoot project and add the following additional dependencies and startup classes to test; overwrite <dependency>
<groupId>com.itranswarp</groupId>
<artifactId>compiler</artifactId>
<version>1.0</version>
</dependency> import com.itranswarp.compiler.JavaStringCompiler;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Map;
@SpringBootApplication
public class DynamicCompilationApplication implements CommandLineRunner {
public static void main(String[] args) throws Exception {
// Initializes the dynamic build class example
buildClassesDynamically();
SpringApplication.run(DynamicCompilationApplication.class, args);
}
/**
* {@link org.springframework.beans.propertyeditors.ClassEditor#setAsText} gets the value here to avoid error
*/
public static Class<?> appClass;
public static Object app;
private static void buildClassesDynamically() throws Exception {
String javaName = "DynamicApplication";
String javaPath = DynamicCompilationApplication.class.getPackage().getName();
JavaStringCompiler javaStringCompiler = new JavaStringCompiler();
Map<String, byte[]> classBytes = javaStringCompiler.compile(javaName + ".java",
"package " + javaPath + ";\n" +
"import org.springframework.boot.CommandLineRunner;" +
"public class " + javaName + " implements CommandLineRunner {" +
"public void run(String... args) { System.err.println(\"Holle Word!\"); }" +
"}"
);
appClass = javaStringCompiler.loadClass(javaPath + "." + javaName, classBytes);
app = appClass.getDeclaredConstructor().newInstance();
}
@Autowired
public ConfigurableApplicationContext context;
@Override
public void run(String... args) throws Exception {
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) context.getBeanFactory();
// case 1: Direct register
String beanName = "dynamic";
// Dynamic type register
beanFactory.registerBeanDefinition(beanName, BeanDefinitionBuilder.genericBeanDefinition(appClass).getRawBeanDefinition());
// Console output:Holle Word!
context.getBean(beanName, CommandLineRunner.class).run(args);
// case 2: Use FactoryBean injection, this will cause an exception
String beanName2 = "factoryDynamic";
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(CustomFactoryBean.class).getRawBeanDefinition();
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(appClass.getName());
beanDefinition.getPropertyValues().add("type", appClass);
beanFactory.registerBeanDefinition(beanName2, beanDefinition);
// TODO : An error will be reported here, and you need to modify the org.springframework.beans.propertyeditors.ClassEditor, as shown below
context.getBean(beanName2, CommandLineRunner.class).run(args);
}
// Like MapperFactoryBean
public static class CustomFactoryBean<T> implements FactoryBean<T> {
private Class<T> type;
public CustomFactoryBean(Class<T> type) {
// TODO :There is also a question, since the parameter construct is called, why is the Setter method called separately again?
this.type = type;
}
public void setType(Class<T> type) {
this.type = type;
}
@Override
public T getObject() throws Exception {
return (T) app;
}
@Override
public Class<?> getObjectType() {
return type;
}
}
} /*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.propertyeditors;
import java.beans.PropertyEditorSupport;
import com.test.dynamic.DynamicCompilationApplication;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Property editor for {@link Class java.lang.Class}, to enable the direct
* population of a {@code Class} property without recourse to having to use a
* String class name property as bridge.
*
* <p>Also supports "java.lang.String[]"-style array class names, in contrast to the
* standard {@link Class#forName(String)} method.
*
* @author Juergen Hoeller
* @author Rick Evans
* @see Class#forName
* @see ClassUtils#forName(String, ClassLoader)
* @since 13.05.2003
*/
public class ClassEditor extends PropertyEditorSupport {
@Nullable
private final ClassLoader classLoader;
/**
* Create a default ClassEditor, using the thread context ClassLoader.
*/
public ClassEditor() {
this(null);
}
/**
* Create a default ClassEditor, using the given ClassLoader.
*
* @param classLoader the ClassLoader to use
* (or {@code null} for the thread context ClassLoader)
*/
public ClassEditor(@Nullable ClassLoader classLoader) {
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasText(text)) {
// TODO Changes
try {
setValue(ClassUtils.resolveClassName(text.trim(), this.classLoader));
} catch (Exception e) {
if (text.equals(DynamicCompilationApplication.appClass.getName())){
setValue(DynamicCompilationApplication.appClass);
} else throw e;
}
} else {
setValue(null);
}
}
@Override
public String getAsText() {
Class<?> clazz = (Class<?>) getValue();
if (clazz != null) {
return ClassUtils.getQualifiedName(clazz);
} else {
return "";
}
}
} |
I don't really understand what you're trying to do. In the second example, you're passing the name of the class but that class doesn't exist. You are the one forcing the editor to kick in an translate the If you're looking for support on using Spring, please ask your question on StackOverflow. |
What's wrong with dynamically compiling a Class? The point is why would FactoryBean inputs be converted to String and then back again, which, performance aside, doesn't seem elegant. Perhaps to be compatible with xml injection Baen, what can be done to bypass this cumbersome transformation? What I need is dynamically compiled classes that can also be registered through FactoryBean, the purpose of which is to simplify repetitive code in a project without breaking its structure (MVC). Cost reduction and efficiency, dynamic and flexible, the future can be expected! |
Nothing, I guess?
You are doing that, not us.
If you have more questions, as I've asked already, please follow up on StackOverflow. |
😳I'm sorry, is my use of error; Thank you for your patient guidance. |
Uh oh!
There was an error while loading. Please reload this page.
In
org.springframework.beans.propertyeditors.ClassEditor
, theClass
is obtained byClassUtils.resolveClassName
as a string, but when theClass
is dynamically generated byjavax.tools.JavaCompiler
, theClass
cannot be obtained byClassUtils.resolveClassName
. Expect to be passed from a primitive type that can be used directly instead of a string conversion, thanks.The text was updated successfully, but these errors were encountered: