解决:Spring中的java.lang.NumberFormatException: null的问题(这是模仿Spring底层Bean注解和Value注解获取值时出现的问题)
一、带你们看一下出现错的截图
二、分析一下为何会出现这个错误
1、从报错来说,应该是括号里面的“变量”是null,当然也就无法转换为Integer类型了
我所写的代码如下:
当然这里的【val】值事先是要通过自定义的Value.class获取到的
2、不管你代码怎么写,只需要注意一个地方
就是你最后要【Integer.parseInt(value);】或者你可以多写一个【Double.parseDouble(value);】
括号里的值value是绝对不能为空的,如果value是null,就会出现截图中的错误,出了这种错误你要看value有没有被赋值即可,再需要注意的是如果你写的不仅仅是【Integer.parseInt(value);】,那你就要检查value也不能是其他无法转换为数字的字符串。
三、eclipse创建的Spring工程结构【Maven仓库配置的】
- 工程名:Spring03Imitate
- src/main/resources
- spring-bean.xml
- src/main/java
- package: com.yc.main.bean
- Person.java
- package: com.yc.main.core
- ApplicationContext.java
- Bean.java
- Value.java
- YcClassPathXmlApplicationContext.java
- package: com.yc.main.test
- SpringTest.java
- package: com.yc.main.bean
- pom.xml
- src/main/resources
四、下面将模仿Spring【自定义Spring】代码分享给大家
spring-bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- 需要扫描的包路径 -->
<component-scan base-package="com.yc.main"></component-scan>
</beans>
Person.java
package com.yc.main.bean;
import com.yc.main.core.Bean;
import com.yc.main.core.Value;
@Bean
public class Person {
@Value("1002")
private String pid;
@Value("W")
private String pname;
@Value("20")
private Integer age;
@Override
public String toString() {
return "Person [pid=" + pid + ", pname=" + pname + ", age=" + age + "]";
}
public String getPid() {
return pid;
}
public void setPid(String pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((pid == null) ? 0 : pid.hashCode());
result = prime * result + ((pname == null) ? 0 : pname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (pid == null) {
if (other.pid != null)
return false;
} else if (!pid.equals(other.pid))
return false;
if (pname == null) {
if (other.pname != null)
return false;
} else if (!pname.equals(other.pname))
return false;
return true;
}
}
ApplicationContext.java
package com.yc.main.core;
public interface ApplicationContext {
public Object getBean(String name);
}
Bean.java
package com.yc.main.core;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Bean {
String value() default "";
}
Value.java
package com.yc.main.core;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Value {
String value() default "";
}
YcClassPathXmlApplicationContext.java
package com.yc.main.core;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
public class YcClassPathXmlApplicationContext implements ApplicationContext {
private static String locationConfig = "spring-bean.xml";
private List<String> classNames = new ArrayList<String>(); // 存放所有扫描的类路径
private Map<String, Object> beans = new HashMap<String, Object>();
public YcClassPathXmlApplicationContext() {
this(locationConfig);
}
public YcClassPathXmlApplicationContext(String config) {
locationConfig = config;
parseXml();
}
/**
* 解析xml文件
*/
@SuppressWarnings("unchecked")
private void parseXml() {
if (locationConfig == null || "".equals(locationConfig)) {
throw new RuntimeException("读取bean的配置文件错误...");
}
SAXReader reader = new SAXReader();
Document doc = null;
try (InputStream is = this.getClass().getClassLoader().getResourceAsStream(locationConfig)) {
doc = reader.read(is);
XPath xpath = doc.createXPath("//component-scan");
List<Element> nodes = xpath.selectNodes(doc);
if (nodes == null || nodes.isEmpty()) {
return;
}
String basePackage = nodes.get(0).attributeValue("base-package");
// 获取这包下的所有类及子包下面的类
doScannerPackage(basePackage);
doInstanceObject(); // 实例化对象
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
/**
* 扫描包
*
* @param basePackage
*/
private void doScannerPackage(String basePackage) {
if (basePackage == null || "".equals(basePackage)) {
throw new RuntimeException("配置文件读取失败,请配置要扫描的包...");
}
URL url = this.getClass().getClassLoader().getResource(basePackage.replaceAll("\\.", "/")); // 将包路径转成目录路径
File file = new File(url.getFile());
if (!file.exists() && !file.isDirectory()) {
throw new RuntimeException("您配置的要扫描的包路径有误...");
}
getClassInfo(basePackage, file);
// classNames.forEach(System.out::println);
}
/**
* 扫描获取包下的类
*
* @param basePackage 这个类的包路径
* @param file 开始扫描的目录
*/
private void getClassInfo(String basePackage, File file) {
if (file.isDirectory()) {
for (File f : file.listFiles()) { // 获取指定目录下在目录或文件
if (f.isDirectory()) {
getClassInfo(basePackage + "." + f.getName(), f);
} else {
classNames.add(basePackage + "." + f.getName().replace(".class", ""));
}
}
}
}
private void doInstanceObject() {
// 先判断哪些上有@Bean注解
if (classNames.isEmpty()) {
return;
}
Class<?> cls = null;
String beanName = null;
Bean bean = null;
Value value = null;
Field[] fields = null;
Object obj = null;
Class<?> type = null;
String val = null;
for (String className : classNames) {
try {
cls = Class.forName(className);
// 现在这个类上有没有这个注解
if (!cls.isAnnotationPresent(Bean.class)) {
continue;
}
obj = cls.newInstance(); // 创建一个对象
bean = cls.getAnnotation(Bean.class);
// 这个注解的value值有给吗
beanName = bean.value();
if ("".equals(beanName)) { // 默认情况下是将整个类的第一个字母转成小写
beanName = toFirstLowerCase(cls.getSimpleName());
}
// 获取整个类下的所有属性
fields = cls.getDeclaredFields();
if (fields == null || fields.length <= 0) {
continue;
}
// 循环判断这些属性有没有Value注解
for (Field fd : fields) {
// 循环判断这些属性上有没有Value注解
value = fd.getAnnotation(Value.class);
if (value == null) {
continue;
}
val = value.value();
if ("".equals(val)) {
continue;
}
//我想给这个属性直接注值,不想调用这个属性的setter方法
fd.setAccessible(true);
//获取这个属性的类型
type = fd.getType();
if (type == Integer.class || type == Integer.TYPE) {
//如果有,则判断Value注解中的value属性有没有给值,如果有则需要注值
fd.set(obj, Integer.parseInt(val));
} else if (type == Double.class || type == Double.TYPE) {
fd.set(obj, Double.parseDouble(val));
} else {
fd.set(obj, val);
}
}
beans.put(beanName, obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
/**
* 将给定字符串的第一个字母转成小写
*
* @param simpleName
* @return
*/
private String toFirstLowerCase(String name) {
char[] chs = name.toCharArray();
chs[0] += 32;
return String.valueOf(chs);
}
@Override
public Object getBean(String name) {
return beans.getOrDefault(name, null);
}
}
SpringTest.java
package com.yc.main.test;
import com.yc.main.bean.Person;
import com.yc.main.core.ApplicationContext;
import com.yc.main.core.YcClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
ApplicationContext ioc = new YcClassPathXmlApplicationContext("spring-bean.xml");
Person person = (Person) ioc.getBean("person");
System.out.println(person);
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yc.main</groupId>
<artifactId>Spring03Imitate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring03Imitate</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
</project>
五、总结
以上就是所有的内容,希望可以帮到大家。
【注意】我所创的只是Maven工程下的视图,创什么工程无所谓,只是Maven仓库对管理一些用到的包比较方便。