I would like to read the array in the YAML file in java spring. I don't know if it's possible to use an array of objects.
Here is the content of the YAML:
main:
nodes:
-
label: "My label"
id: "My label id"
uri: ""
-
label: "My label"
id: "My label id"
uri: ""
And here is my component which loads the file:
public class MyNode {
String label, id, uri;
}
#ConfigurationProperties(prefix = "main")
#PropertySource(value = "classpath:mycustomfile.yml", factory = YamlPropertyLoaderFactory.class)
#Component
public class CustomProperties {
private List<MyNode> nodes;
}
And the YamlPropertySourceFactory
public class YamlPropertySourceFactory implements PropertySourceFactory {
#Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
}
When I run my application, nodes are null. I followed Baeldun tutorial
I solved it by adding #Data (Lombok) and make MyNode as inner static class. You can also add getter and setter if you don't use Lombok.
#ConfigurationProperties(prefix = "main")
#PropertySource(value = "classpath:mycustomfile.yml", factory = YamlPropertyLoaderFactory.class)
#Component
public class CustomProperties {
private List<MyNode> nodes;
#Data
public static class MyNode {
private String label, id, uri;
}
}
It seems that the problem comes from the visibility of your MyNode class members.
If you define public setters for all the members, everything will work fine.
So just try to modify
public class MyNode {
String label, id, uri;
}
to
public class MyNode {
private String label, id, uri;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}
Related
Refer to the seven security areas outlined in the Vulnerability Assessment Process Flow Diagram. Use what you’ve learned in steps 1 and 2 to guide your manual review. Identify all vulnerabilities in the Project One Code Base, linked in Supporting Materials, by manually inspecting the code. Document your findings in your vulnerability assessment report. Be sure to include a description that identifies where the vulnerabilities are found (specific class file, if applicable).
Vulnerability Process Flow Diagram
#SpringBootApplication
public class RestServiceApplication {
public static void main(String[] args) {
SpringApplication.run(RestServiceApplication.class, args);
}
}
public class myDateTime {
int mySecond;
int myMinute;
int myHour;
int[] retrieveDateTime() {
/* implement accessor method */
return new int[3];
}
void setMyDateTime(int seconds, int minutes, int hour) {
/* implement accessor method */
}
}
#RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
}
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
public class customer {
private int account_number;
int account_balance;
public int showInfo() {
//code to show customer information
return this.account_number;
}
public void deposit(int a) {
account_balance = account_balance + a;
}
}
#RestController
public class CRUDController {
#RequestMapping("/read")
public CRUD CRUD(#RequestParam(value="business_name") String name) {
DocData doc = new DocData();
return new CRUD(doc.toString());
}
}
public class CRUD {
private final String content;
private final String content2;
public CRUD(String content) {
this.content = content;
this.content2 = content;
}
public CRUD(String content1, String content2) {
this.content = content1;
this.content2 = content2;
}
public String getContent() {
return content;
}
public String getContent2() {
return content2;
}
}
Honestly, I am just confused about what I am doing and looking for in the code for it to be classified as a vulnerability. Anything helps, thanks.
I am working on a microservice in Spring Boot, and I have a common configuration class where I store all the config variabes that I got from application.properties file. It looks something like this:
Config.java
package programming
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
#Configuration
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CommonConfiguration {
#Value("${user-pool.id}")
private String userPoolId;
#Value("${client.id}")
private String clientId;
...
...
...
}
Then whenever I need these variables in other classes, I autowire Config.java class, and simply use it like this:
#Autowired
private Config config;
public void method1() {
...
String key = items.get(config.getClientId()).toString();
}
Would having a common configuration class that stores all the autowired variables and use these when needed in other classes a good practice in spring boot? If not, what would be the best way to go about this? Any help would be greatly appreicated. Thank you!
The better way is to do something ging like this
#ConfigurationProperties(prefix = "optional.key")
Public class MyProperties{
Int example;
String example2;
Getters/setters
}
In your application.properties you can now type
optional.key.example=5
You can the Autowerire MyProperties where ever you need them
Edit
It’s also good to add the following dependency to maven, it generates a helper file so that your idea can recognise the defined properties
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Small addition to replay on the question in the comments
You can leave the prefix empty and just annotate you class with #ConfigurationProperties if you don't want to have a general key
Subkeys can be easily handled with subclasses I will post an example of one of my projects here
#ConfigurationProperties(prefix = "swagger")
public class SpringFoxProperties {
private Info info = new Info();
private Config config = new Config();
public Info getInfo() {
return info;
}
public void setInfo(Info info) {
this.info = info;
}
public Config getConfig(){
return config;
}
public void setConfig(Config config) {
this.config = config;
}
public static class Config {
private String paths = "";
private String documentationType = "openApi";
public String getPaths() {
return paths;
}
public void setPaths(String paths) {
this.paths = paths;
}
public String getDocumentationType() {
return documentationType;
}
public void setDocumentationType(String documentationType) {
this.documentationType = documentationType;
}
}
public static class Info {
private String title = "";
private String description = "";
private String version = "";
private String termsOfServiceUrl = "";
private Contact contact = new Contact();
private License license = new License();
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getTermsOfServiceUrl() {
return termsOfServiceUrl;
}
public void setTermsOfServiceUrl(String termsOfServiceUrl) {
this.termsOfServiceUrl = termsOfServiceUrl;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public License getLicense() {
return license;
}
public void setLicense(License license) {
this.license = license;
}
public static class Contact {
private String name = "";
private String url = "";
private String email = "";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
public static class License {
private String name = "";
private String url = "";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
}
}
example application.yml
swagger:
info:
title: title
description: description
version: version
termsOfServiceUrl: termsOfServiceUrl
contact:
name: name
url: url
email: email
license:
name: name
url: url
config:
paths: /api/.*
documentation-type: swagger
Would having a common configuration class that stores all the autowired variables and use these when needed in other classes a good practice in spring boot? If not, what would be the best way to go about this? Any help would be greatly appreicated.
My answer to that part is: definitely no!
You are introducing a real class dependency for all classes that need configuration. With that you are actually reversing the configuration injection that spring offers.
The whole point is to be able to inject only that specific part of the configuration you need in fields of your target class directly (e.g. by using #Value("${foo.bar}" private String fooBar;))
With that you also disable use of specific features (e.g. using a different profile in different classes with #Profile), and i'm sure there are more examples that you are actually limiting the flexibility.
I don't see any benefit in your approach - you may aswell explain why you need that :)
I discovered the #JsonTypeInfo annotation via https://www.baeldung.com/jackson-annotations and tried to use this in order to dynamically parse a given YAML-file into different POJOs. The YAML could look like this:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
AWSSNSTopic:
Properties:
Subscription:
Endpoint: someEnpointInfo
Protocol: email
ResourceName: HelloWorldTopic
Type: AWS::SNS::Topic
AWSServerlessFunction:
Properties:
Attributes: SomeString
ResourceName: HelloWorldFunction
Type: AWS::Serverless::Function
Transform: AWS::Serverless-2016-10-31
What I want to do is to parse the Resources dynamically since the properties of the objects inside Resources are dependent of the property Type but cannot be implicated by the keys (such as AWSSNSTopic or AWSServerlessFunction which only happen to be consistent with the type in this case but do not have to).
So I tried to solve this somehow via #JsonSubTypes to track down the Type property and decide what type of POJO this will be mapped on. This could look like follows:
public class AWSLambdaResource {
#JsonProperty("AWSTemplateFormatVersion")
private String AWSTemplateFormatVersion;
#JsonProperty("Transform")
private String Transform;
#JsonProperty("Resources")
private Map<String, Ressource> Resources;
public String getAWSTemplateFormatVersion() {
return AWSTemplateFormatVersion;
}
public void setAWSTemplateFormatVersion(String AWSTemplateFormatVersion) {
this.AWSTemplateFormatVersion = AWSTemplateFormatVersion;
}
public String getTransform() {
return Transform;
}
public void setTransform(String Transform) {
this.Transform = Transform;
}
public Map<String, Ressource> getResources() {
return Resources;
}
public void setResources(Map<String, Ressource> resources) {
Resources = resources;
}
}
public class Ressource {
public ResourceInstance resourceInstance;
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "Type")
#JsonSubTypes({
#JsonSubTypes.Type(value = AWSServerlessFunction.class, name = "AWS::Serverless::Function"),
#JsonSubTypes.Type(value = AWSSNSTopic.class, name = "AWS::SNS::Topic")
})
public static class ResourceInstance {
#JsonProperty("Type")
public String type;
#JsonProperty("ResourceName")
public String resourceName;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
}
#JsonTypeName("AWSServerlessFunction")
public static class AWSServerlessFunction extends ResourceInstance {
#JsonProperty("ResourceName")
private String resourceName;
#JsonProperty("Properties")
private Properties properties;
public static class Properties {
#JsonProperty("Attributes")
public String attributes;
public String getAttributes() {
return attributes;
}
public void setAttributes(String attributes) {
this.attributes = attributes;
}
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
#JsonTypeName("AWSSNSTopic")
public static class AWSSNSTopic extends ResourceInstance {
#JsonProperty("Subscription")
public Subscription subscription;
public static class Subscription {
#JsonProperty("Endpoint")
public String endpoint;
#JsonProperty("Protocol")
public String protocol;
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
}
public Subscription getSubscription() {
return subscription;
}
public void setSubscription(Subscription subscription) {
this.subscription = subscription;
}
}
public ResourceInstance getResourceInstance() {
return resourceInstance;
}
public void setResourceInstance(ResourceInstance resourceInstance) {
this.resourceInstance = resourceInstance;
}
}
However, when I look into the map there are entries with keys AWSSNSTopic and AWSServerlessFunction but the corresponding resourceInstance objects are null.
Where did I go wrong? Or is this simply not possible to solve with this type of approach?
I want to parse a JSON document with Jackson and apply some transformation on all nodes. For example, let's say that I want all values to be in uppercase after deserialization.
The actual use case is a bit more complex:
transformation is more complex, the transformer class need to be injected with some configuration, I'd like it to be a configureable instance
transformation has to happen on all properties, I'd like to be able to not add an annotation on each property of each class deserialized.
There are enough configuration options / hooks in Jackson, so I'm fairly sure that this is possible, I just can't find my way around.
The test below shows what I'm trying to achieve:
public class JsonValueFilterTest {
private ObjectMapper mapper;
#Before
public void setupObjectMapper() {
mapper = new ObjectMapper();
// TODO: configure mapper to upper case all values
}
#Test
public void printJson() throws IOException {
Entity myEntity = new Entity("myName");
mapper.writeValue(System.out, myEntity); // prints: {"name":"myName"}
}
#Test
public void valuesAreUpperCasedWhenLoaded() throws IOException {
Entity myEntity = mapper.readValue("{\"name\":\"myName\"}", Entity.class);
assertThat(myEntity.getName()).isEqualTo("MYNAME"); // fails
}
public static class Entity {
private final String name;
#JsonCreator
public Entity(#JsonProperty("name") String name) { this.name = name; }
public String getName() { return name; }
#Override
public String toString() { return "name='" + name + "'"; }
}
}
You can use converter for that simple case to not implement custom deserializer. I don't know why, but It's not working on the creator constructors, though. So you will have to use non-final fields.
public class JsonValueFilterTest {
private ObjectMapper mapper;
#BeforeTest
public void setupObjectMapper() {
mapper = new ObjectMapper();
}
#Test
public void printJson() throws IOException {
Entity myEntity = new Entity("myName");
mapper.writeValue(System.out, myEntity); // prints: {"name":"myName"}
}
#Test
public void valuesAreUpperCasedWhenLoaded() throws IOException {
Entity myEntity = mapper.readValue("{\"name\":\"myName\"}", Entity.class);
Assert.assertEquals(myEntity.getName(), "MYNAME"); // fails
}
public static class UpCaseConverter extends StdConverter<String, String> {
public String convert(String value) {
return value==null ? null : value.toUpperCase();
}
}
public static class Entity {
private String name;
public Entity() {}
public Entity(String name) {
this.name = name;
}
#JsonDeserialize(converter = UpCaseConverter.class)
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "name='" + name + "'";
}
}
}
My final solution (thanks to Alban):
configure the ObjectMapper with a custom JsonNodeFactory which transforms all text nodes
deserialize json to JsonNode (this will apply transformation)
convert the JsonNode to my custom class
public class JsonValueFilterTest {
private ObjectMapper mapper;
#Before
public void setupObjectMapper() {
mapper = new ObjectMapper();
mapper.setNodeFactory(new JsonNodeFactory() {
#Override
public TextNode textNode(String text) {
return super.textNode(text.toUpperCase());
}
});
}
#Test
public void printJson() throws IOException {
Entity myEntity = new Entity("myName");
mapper.writeValue(System.out, myEntity); // prints: {"name":"myName"}
}
#Test
public void valuesAreUpperCasedWhenLoaded() throws IOException {
JsonNode jsonNode = mapper.readTree("{\"name\":\"myName\"}");
Entity myEntity = mapper.treeToValue(jsonNode, Entity.class);
assertThat(myEntity.getName()).isEqualTo("MYNAME");
}
public static class Entity {
private final String name;
#JsonCreator
public Entity(#JsonProperty("name") String name) { this.name = name; }
public String getName() { return name; }
#Override
public String toString() { return "name='" + name + "'"; }
}
}
I'm being given a Json file with the form:
{
"descriptions": {
"desc1": "someString",
"desc2": {"name":"someName", "val": 7.0}
}
}
I have the POJO:
public class CustomClass {
Map<String, Object> descriptions;
public static class NameVal{
String name;
double val;
public NameVal(String name, double val){...}
}
}
I can recreate the json file with the code:
CustomClass a = new CustomClass();
a.descriptions = new HashMap<String, Object>();
a.descriptions.put("desc1", "someString");
a.descriptions.put("desc2", new CustomClass.NameVal("someName", 7.0));
new ObjectMapper().writeValue(new File("testfile"), a);
But, when I read the object back in using:
CustomClass fromFile = new ObjectMapper().readValue(new File("testfile"), CustomClass.class);
then fromFile.descriptions.get("desc2") is of type LinkedHashMap instead of type CustomClass.NameVal.
How can I get Jackson to properly parse the type of the CustomClass.NameVal descriptors (other than making some class that wraps the parsing and explicitly converts the LinkedHashMap after Jackson reads the file)?
Try this. Create a class Description with name and value attributes:
public class Description {
private String name;
private double val;
}
Now in your CustomClass do this:
public class CustomClass {
List<Description> descriptions;
}
And that's it. Remember to create getters and setters because Jackson needs it.
You could try something like this:
public class DescriptionWrapper {
private Description descriptions;
public Description getDescriptions() {
return descriptions;
}
public void setDescriptions(Description descriptions) {
this.descriptions = descriptions;
}
}
public class Description {
private String desc1;
private NameValue desc2;
public String getDesc1() {
return desc1;
}
public void setDesc1(String desc1) {
this.desc1 = desc1;
}
public NameValue getDesc2() {
return desc2;
}
public void setDesc2(NameValue desc2) {
this.desc2 = desc2;
}
}
public class NameValue {
private String name;
private double val;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getVal() {
return val;
}
public void setVal(double val) {
this.val = val;
}
}