Skip to content

Commit

Permalink
feat: JsonPropertySourceFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
ahunigel committed Mar 22, 2020
1 parent cb3f33a commit 9d2bc58
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 25 deletions.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ Notes: All the testing features are moved to https://github.com/ahunigel/spring-

## Features
- `YamlPropertySourceFactory`
- Spring `@PropertySource` does not support yaml by default, this factory help load yaml
- Spring `@PropertySource` does not support `yml` and `yaml` by default, this factory help load yaml files
- `ReversibleConverter<A, B>`
- reverse converter with `.reverse()` method
- functional converter, used for java `stream` mapping
- instance of spring converter
- `BeanUtilEx`
- Enhance the spring `BeanUtils`, provide `Predicate` as name or value filters for copy properties
- `JsonPropertySourceFactory`
- Spring `@PropertySource` does not support `json` by default, this factory help load json files

## How to use

Expand All @@ -36,7 +38,7 @@ _Refer to https://jitpack.io/#ahunigel/spring-toolkit for details._

## Step 3. Sample code
```java
@PropertySource(value = "classpath:custom.yml", factory = YamlPropertySourceFactory.class)
@PropertySource(value = {"classpath:custom.yml", "classpath:custom2.yml"}, factory = YamlPropertySourceFactory.class)
public class FooApplication {}
```

Expand Down Expand Up @@ -65,6 +67,13 @@ converter.reverse().convertAll(booList).forEach(f -> assertThat(f).isNotNull().i
```java
BeanUtilEx.copyProperties(foo, target, name -> name.length() > 1, Objects::nonNull);
```

```java
@PropertySource(value = {"classpath:custom.json", "classpath:custom.json"}, factory = JsonPropertySourceFactory.class)
public class FooApplication {}
```


## References
- [Using YAML Instead of Properties](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-yaml)
- [Spring @PropertySource using YAML](https://stackoverflow.com/questions/21271468/spring-propertysource-using-yaml)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.github.ahunigel.json;

import com.github.ahunigel.util.ResourceUtil;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;

import java.io.IOException;

/**
* Created by nigel on 2020/3/21.
*
* @author nigel
*/
public class JsonPropertySourceFactory implements PropertySourceFactory {
private PropertySourceLoader sourceLoader = new JsonPropertySourceLoader();

@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
return ResourceUtil.loadPropertySource(name, resource, sourceLoader);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.github.ahunigel.json;

import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
* Created by nigel on 2020/3/22.
*
* @author nigel
*/
public class JsonPropertySourceLoader implements PropertySourceLoader {
@Override
public String[] getFileExtensions() {
return new String[]{"json"};
}

@Override
public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
List<Map<String, ?>> loaded = new OriginTrackedJsonLoader(resource).loadAsYaml();
if (loaded.isEmpty()) {
return Collections.emptyList();
}
List<PropertySource<?>> propertySources = new ArrayList<>(loaded.size());
for (int i = 0; i < loaded.size(); i++) {
propertySources.add(new OriginTrackedMapPropertySource(
name + (loaded.size() != 1 ? " (document #" + i + ")" : ""),
loaded.get(i)));
}

return propertySources;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.github.ahunigel.json;

import com.github.ahunigel.yaml.YamlResourceUtil;
import com.google.common.io.Files;
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
* Created by nigel on 2020/3/22.
*
* @author nigel
*/
public class OriginTrackedJsonLoader {
private final Resource resource;

public OriginTrackedJsonLoader(Resource resource) {
this.resource = resource;
}

public List<Map<String, ?>> load() throws IOException {
JsonParser parser = JsonParserFactory.getJsonParser();
String json = Files.toString(resource.getFile(), StandardCharsets.UTF_8);
Map<String, ?> map = parser.parseMap(json);
return Collections.singletonList(map);
}

public List<Map<String, ?>> loadAsYaml() {
Map<String, ?> properties = (Map) YamlResourceUtil.toProperties(resource);
if (properties.isEmpty()) {
return Collections.emptyList();
}
return Collections.singletonList(properties);
}
}
22 changes: 22 additions & 0 deletions src/main/java/com/github/ahunigel/util/ResourceUtil.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.github.ahunigel.util;

import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.List;

/**
* Created by nigel on 2018/8/14.
*
Expand All @@ -26,4 +31,21 @@ public static String getNameForResource(Resource resource) {
}
return name;
}

public static PropertySource<?> loadPropertySource(String name, EncodedResource resource,
PropertySourceLoader sourceLoader) throws IOException {
String resourceName = getName(name, resource);
List<PropertySource<?>> testProperties = sourceLoader.load(resourceName, resource.getResource());
PropertySource<?> propertySource = testProperties.stream().findFirst().orElse(null);

return propertySource;
}

public static String getName(String name, EncodedResource resource) {
return name != null ? name : getNameForResource(resource.getResource());
}

public static String getName(String name, Resource resource) {
return name != null ? name : getNameForResource(resource);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.github.ahunigel.yaml;

import com.github.ahunigel.util.ResourceUtil;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;

import java.io.IOException;
import java.util.List;

/**
* Created by nigel on 2018/8/9.
Expand All @@ -16,15 +16,11 @@
*/
public class YamlPropertySourceFactory implements PropertySourceFactory {

private YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
private PropertySourceLoader sourceLoader = new YamlPropertySourceLoader();

@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
String resourceName = name != null ? name : ResourceUtil.getNameForResource(resource.getResource());
List<PropertySource<?>> yamlTestProperties = sourceLoader.load(resourceName, resource.getResource());
PropertySource<?> yamlPropertySource = yamlTestProperties.stream().findFirst().orElse(null);

return yamlPropertySource;
return ResourceUtil.loadPropertySource(name, resource, sourceLoader);
}

}
19 changes: 6 additions & 13 deletions src/main/java/com/github/ahunigel/yaml/YamlResourceUtil.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.github.ahunigel.yaml;

import com.github.ahunigel.util.ResourceUtil;
import org.springframework.beans.factory.config.YamlMapFactoryBean;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.MapPropertySource;
Expand All @@ -11,6 +10,8 @@
import java.util.Map;
import java.util.Properties;

import static com.github.ahunigel.util.ResourceUtil.getName;

/**
* Created by nigel on 2018/8/14.
*
Expand All @@ -33,11 +34,11 @@ public static Properties toProperties(Resource resource) {
}

public static PropertiesPropertySource toPropertiesSource(EncodedResource resource, String name) {
return new PropertiesPropertySource(getResourceName(resource, name), toProperties(resource));
return toPropertiesSource(resource.getResource(), name);
}

public static PropertiesPropertySource toPropertiesSource(Resource resource, String name) {
return new PropertiesPropertySource(getResourceName(resource, name), toProperties(resource));
return new PropertiesPropertySource(getName(name, resource), toProperties(resource));
}

public static Map<String, Object> toMap(EncodedResource resource) {
Expand All @@ -51,19 +52,11 @@ public static Map<String, Object> toMap(Resource resource) {
}

public static MapPropertySource toMapSource(EncodedResource resource, String name) {
return new MapPropertySource(getResourceName(resource, name), toMap(resource));
return toMapSource(resource.getResource(), name);
}

public static MapPropertySource toMapSource(Resource resource, String name) {
return new MapPropertySource(getResourceName(resource, name), toMap(resource));
}

private static String getResourceName(EncodedResource resource, String name) {
return name != null ? name : ResourceUtil.getNameForResource(resource);
}

private static String getResourceName(Resource resource, String name) {
return name != null ? name : ResourceUtil.getNameForResource(resource);
return new MapPropertySource(getName(name, resource), toMap(resource));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.github.ahunigel.json;

import com.github.ahunigel.TestApp;
import com.github.ahunigel.TestDevice;
import lombok.SneakyThrows;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Created by nigel on 2020/3/21.
*
* @author nigel
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = {TestApp.class, TestDevice.class})
@AutoConfigureWebMvc
@PropertySource(value = {"classpath:test.json", "classpath:test-device.json"}, factory = JsonPropertySourceFactory.class)
public class JsonPropertySourceFactoryTest {
@Autowired
private Environment environment;
@Autowired
private TestDevice testDevice;
@Value("${nz.int}")
private int nzInt;
@Value("${nz.float}")
private float nzFloat;
@Value("${nz.string}")
private String nzString;

@SneakyThrows
@Test
public void testBean() {
TestDevice expectDevice = new TestDevice();
expectDevice.setIp("192.168.168.1");
expectDevice.setPort(8080);
expectDevice.setPortSsl(8443);
expectDevice.setUserName("nigel");
expectDevice.setPassword("zheng");
expectDevice.setMainApi("app/index.php");

assertThat(testDevice).isEqualTo(expectDevice);
}

@SneakyThrows
@Test
public void testEnv() {
assertThat(environment.getProperty("nz.int")).isNotNull().isEqualTo("5");
assertThat(environment.getProperty("nz.float")).isNotNull().isEqualTo("6.0");
assertThat(environment.getProperty("nz.string")).isNotNull().isEqualTo("nigel");
}

@SneakyThrows
@Test
public void testValueAnnotation() {
assertThat(nzInt).isNotZero().isEqualTo(5);
assertThat(nzFloat).isNotNaN().isEqualTo(6.0f);
assertThat(nzString).isNotNull().isEqualTo("nigel");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -23,9 +22,8 @@
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = {TestApp.class, TestDevice.class})
@TestPropertySource("classpath:test.properties")
@AutoConfigureWebMvc
@PropertySource(value = "classpath:test.yml", factory = YamlPropertySourceFactory.class)
@PropertySource(value = {"classpath:test.yml", "classpath:test-device.yml"}, factory = YamlPropertySourceFactory.class)
public class YamlPropertySourceFactoryTest {
@Autowired
private Environment environment;
Expand Down
10 changes: 10 additions & 0 deletions src/test/resources/test-device.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"test.device": {
"ip": "192.168.168.1",
"port": 8080,
"portSSL": 8443,
"username": "nigel",
"password": "zheng",
"mainApi": "app/index.php"
}
}
8 changes: 8 additions & 0 deletions src/test/resources/test-device.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
test:
device:
ip: 192.168.168.1
port: 8080
portSSL: 8443
username: nigel
password: zheng
mainApi: app/index.php
7 changes: 7 additions & 0 deletions src/test/resources/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"nz": {
"int": 5,
"float": 6.0,
"string": "nigel"
}
}
4 changes: 4 additions & 0 deletions src/test/resources/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
nz:
int: 5
float: 6.0
string: nigel

0 comments on commit 9d2bc58

Please sign in to comment.