I am trying to create a Map<String, Product> from my .properties file in Spring boot 3.1. I have written my custom converter for this, but it seems that it is never executing. I haven't done custom conversions before and I am not sure if a converter is needed in this use case or if Spring boot is able to manage the conversion automagically (If I configure it correctly).
product-configurations.properties:
products.product[0].name=FirstProduct
products.product[0].productID=1234
products.product[0].availableOptions=Opt1
products.product[0].processing=Parallel
Product class:
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
public class Product {
private String name;
private String processing;
private String availableOptions;
private Integer productID;
}
Configuration class:
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import lombok.Getter;
import lombok.Setter;
#Configuration
#PropertySource("classpath:product-configurations.properties")
#ConfigurationProperties("products")
#Getter
#Setter
public class ProductProperties {
private List<Product> product;
}
ProductConverter class:
import java.util.List;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import com.cb.clientfacingapp.model.Product;
#Component
#ConfigurationPropertiesBinding
public class ProductConverter implements Converter<List<Product>, Map<String, Product>> {
#Override
public Map<String, Product> convert(List<Product> source) {
Product p = new Product();
System.out.println("I am converting");
return null;
}
}
Can someone pls guide me on this?
Thanks in Advance.
Update:
Sorry, I forgot to mention how the map should be organized.
Map<String, Product> where String is basically the name property of the product, and Product is the POJO class for that specific product, So each Product is mapped to its Name, basically.
Seems like what you're trying to achieve can be done without conversion
root.products.productName1.name=FirstProduct
root.products.productName1.productID=1234
root.products.productName1.availableOptions=Opt1
root.products.productName1.processing=Parallel
root.products.productName2.name=SecondProduct
root.products.productName2.productID=5678
root.products.productName2.availableOptions=Opt2
root.products.productName2.processing=Parallel
Therefore productName1, productName2 would be your map key names.
You can use it this way:
#ConfigurationProperties("root")
#Getter
#Setter
public class ProductProperties {
private Map<String, Product> products;
}
You could do what #Daria has suggested, which is the simplier way to do it.
In case you're still wondering how to convert a list into a Map, it can be done using Streams:
import java.util.List;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import com.cb.clientfacingapp.model.Product;
#Component
#ConfigurationPropertiesBinding
public class ProductConverter implements Converter<List<Product>, Map<String, Product>> {
#Override
public Map<String, Product> convert(List<Product> source) {
return source.stream().collect(
Collectors.toMap(Product::getName,Function.identity));
}
}
It would generate a map with the product name as key value, and the product object as content value.
Related
I'm trying to update the tagline of a movie node
This is my Movie class without the boilerplate section
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
#Node
public class Movie {
#Id
public String title;
public String tagline;
}
This is my movie repository. I'm including also all the imports just to be sure that I'm passing as much info as possible to hum might answer this question
package com.prompto.api4.movies;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;
import java.util.List;
interface MovieRepository extends Neo4jRepository<Movie, String> {
}
And this is how I try to create/update a specific movie. But sadly this approach only works fro create.
package com.prompto.api4.movies;
import org.neo4j.driver.*;
import org.neo4j.driver.types.TypeSystem;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
#Service
public class MovieService {
private final MovieRepository movieRepository;
private final Neo4jClient neo4jClient;
private final Driver driver;
private final DatabaseSelectionProvider databaseSelectionProvider;
MovieService(MovieRepository movieRepository,
Neo4jClient neo4jClient,
Driver driver,
DatabaseSelectionProvider databaseSelectionProvider) {
this.movieRepository = movieRepository;
this.neo4jClient = neo4jClient;
this.driver = driver;
this.databaseSelectionProvider = databaseSelectionProvider;
}
#Transactional
public void createUpdateMovie(Movie movieValues){
Optional<Movie> theMovie = movieRepository.findById(movieValues.title);
if (theMovie.isPresent()){
theMovie.get().setTagline(movieValues.tagline);
}else {
movieRepository.save(movieValues);
}
}
}
The creating part is working but the update part does not.
How do I update the movie tagline?
I am working in a project to learn spring boot, i have a problem where i have a attribute actor_id stored in mongodb with a value x but when i do mongoRepository.findall(), he changes the value of my actor_id to the value of the object_id generated automatically by mongodb, so even if i want to find a value by id i have to put the object_id value instead of the value of actor_id stored in database. Image below to better help understand.
I wanted that the returned value of a get http://localhost:8093/actors in actor_id be = 1 instead of 61634ad37e775d4b87635129.
Below is my code.
Actor.java:
package com.film.SpringAplication.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
String actor_id;
String first_name;
String last_name;
}
ActorController.java
package com.film.SpringAplication.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.film.SpringAplication.model.Actor;
import com.film.SpringAplication.service.ActorService;
#RestController
#RequestMapping("/actors")
public class ActorController {
#Autowired
ActorService actorService;
#PostMapping
public String addActor(#RequestBody Actor actor) {
return actorService.addActor(actor);
}
#GetMapping
public List<Actor> getActors() {
return actorService.getActors();
}
#GetMapping("/{id}")
public List<Actor> getActor(#PathVariable String id) {
return actorService.getActor(id);
}
#DeleteMapping("/{id}")
public String deleteActor(#PathVariable String id) {
return actorService.deleteActor(id);
}
}
ActorService.java:
package com.film.SpringAplication.service;
import java.util.List;
import java.util.Optional;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import com.film.SpringAplication.model.Actor;
import com.film.SpringAplication.repository.ActorRepository;
import lombok.RequiredArgsConstructor;
#Service
#RequiredArgsConstructor
public class ActorService {
private final ActorRepository actorRepository;
private final MongoTemplate mongoTemplate;
public String addActor(Actor actor) {
actorRepository.save(actor);
return "Actor Added";
}
public List<Actor> getActors() {
List<Actor> lista = actorRepository.findAll();
return lista;
}
public List<Actor> getActor(String id) {
Query query=new Query()
.addCriteria(Criteria.where("actor_id").is(id));
return mongoTemplate.find(query,Actor.class);
//return actorRepository.findById(id);
}
public String deleteActor(String id) {
actorRepository.deleteById(id);
return "User deleted";
}
}
ActorRepository.java:
package com.film.SpringAplication.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.film.SpringAplication.model.Actor;
public interface ActorRepository extends MongoRepository<Actor,String>{
}
What you can do is, you can use #Field. You annotate #Id to actor_id. So basically it takes as the default primary key. You can do two things. You can annotate _id as default primary key.
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
ObjectId _id;
String actor_id;
String first_name;
String last_name;
}
Else you can annotate #Field
#Document(collection="actor")
#AllArgsConstructor
#Data
public class Actor {
#Id
#Field("actor_id")
String actor_id;
String first_name;
String last_name;
}
Related answer
I am aware that there are a lot of questions related to the same but none of them worked for some reason. Hence, posting the same and hoping to get some response.
I am trying to follow the SpingBoot application tutorial from Youtube and build the same application. But for some reason I get following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field postRepository in com.testingconverter.service.PostService required a bean of type 'com.testingconverter.repository.PostRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.testingconverter.repository.PostRepository' in your configuration.
Following are my classes:
Main SpringBootApplication class:
package com.testingconverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
public class TestingConverterApplication {
public static void main(String[] args) {
SpringApplication.run(TestingConverterApplication.class, args);
}
}
Controller class:
package com.testingconverter.controller;
import com.testingconverter.entities.PostEntity;
import com.testingconverter.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
public class BlogController {
#Autowired
private PostService postService;
#GetMapping(value = "/")
public String index() {
return "index";
}
#GetMapping(value = "/posts")
public List<PostEntity> posts() {
return postService.getAllPost();
}
#PostMapping(value = "/posts")
public void publishPost(#RequestBody PostEntity post) {
postService.insert(post);
}
}
My Entity class:
package com.testingconverter.entities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Date;
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class PostEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String title;
private String body;
private Date date;
}
My Repository class:
package com.testingconverter.repository;
import com.testingconverter.entities.PostEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface PostRepository extends JpaRepository<PostEntity, Long> {
}
My Service class:
package com.testingconverter.service;
import com.testingconverter.entities.PostEntity;
import com.testingconverter.repository.PostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class PostService {
#Autowired
private PostRepository postRepository;
public List<PostEntity> getAllPost() {
return postRepository.findAll();
}
public void insert(PostEntity post) {
postRepository.save(post);
}
}
I tried many things like adding the #ComponentScan etc but nothing seems to work for me. Can someone please explain to me what's going wrong here? How can I fix this?
Following is my project structure:
You excluding default database configuration. Remove that exclude part and add your database configuration in application properties files.
If you going to exclude then you have to create you datasource in configuration file.
#Bean
public DataSource getDataSource() {
DataSourceBuilder dataSourceBuilder =
DataSourceBuilder.create();
dataSourceBuilder.driverClassName("");
dataSourceBuilder.url("");
dataSourceBuilder.username("");
dataSourceBuilder.password("");
return dataSourceBuilder.build();
}
I'm try to connect java spring boot with mysql. when i run the code i got the map address like this
This is my first code
This is EmpController1
package com.example.rest.controller;
import com.example.rest.repository.R1pro;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.rest.repository.EmpRepository1;
import java.util.ArrayList;
import java.util.List;
#RestController
#RequestMapping(value = "/emp")
#Slf4j
public class EmpController1 {
#Autowired
private EmpRepository1 empRepository1;
#RequestMapping(value="/ee", method = RequestMethod.GET)
#ResponseBody
public String getCategoryList() {
List<String> sj = new ArrayList<String>();
Gson gson= new Gson();
System.out.println(123);
List<R1pro> emps1 = this.empRepository1.findByLimit();
return emps1.toString();
}
}
This is my EmpRepository1 code
package com.example.rest.repository;
import com.example.rest.Emp;
import com.example.rest.Emp1;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface EmpRepository1 extends JpaRepository<Emp1, Integer> {
#Query(value = "select * from d_RANGE limit 1",nativeQuery = true)
public List<R1pro> findByLimit();
}
This is R1pro code
package com.example.rest.repository;
import java.util.Date;
public interface R1pro {
public String USER_ID();
public String CUST_GP();
}
This is my Emp1 code
package com.example.rest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Date;
import java.sql.Timestamp;
#Entity
#Table(name = "TEMP_TEST_M78_2W")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Emp1 {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String USER_ID;
private String CUST_GP;
}
This is my Application code
package com.example.rest;
import com.example.rest.repository.EmpRepository;
import com.example.rest.repository.EmpRepository1;
import com.example.rest.repository.R1pro;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import java.util.List;
#SpringBootApplication
#Slf4j
public class Application {
#Autowired
EmpRepository empRepository;
#Autowired
EmpRepository1 empRepository1;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
CommandLineRunner start() {
return args -> {mysql();};
}
private void mysql() {
List<R1pro> emp1 = this.empRepository1.findByLimit();
}
}
When i run the code i got this result
[org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap#27ae5583]
So i change the EmpController1 code
package com.example.rest.controller;
import com.example.rest.repository.R1pro;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.rest.repository.EmpRepository1;
import java.util.ArrayList;
import java.util.List;
#RestController
#RequestMapping(value = "/emp")
#Slf4j
public class EmpController1 {
#Autowired
private EmpRepository1 empRepository1;
#RequestMapping(value="/ee", method = RequestMethod.GET)
#ResponseBody
public String getCategoryList() {
List<String> sj = new ArrayList<String>();
Gson gson= new Gson();
System.out.println(123);
List<R1pro> emps1 = this.empRepository1.findByLimit();
for (int i =0; i<emps1.size();i++)
{
sj.add(emps1.get(i).USER_ID()+" "+ emps1.get(i).CUST_GP());
}
return sj.toString();
}
}
When i run the code i got this Error message
java.lang.IllegalArgumentException: Invoked method public abstract java.lang.String com.example.rest.repository.R1pro.USER_ID() is no accessor method!
Actually this method same as mysql data columns
USER_ID varchar(150)
CUST_GP varchar(1)
This is my sql columns informations
I don't know what is the problem also any solution.. so if someone knows that please teach me
I really admire to solve this issue
thank you!
You need to tweak your interface into something like this -
public interface R1pro {
String getUSER_ID();
String getCUST_GP();
}
The resultset is mapped only to the getter methods similar to the one created in Emp1 class
I have written oauth2 social client but could not fetch authorized user's friends list
Please have a look at my code to see what's missing/
regards
please look at #RequestMapping("vkontakte/friends")
java 1.8 spring security
#SpringBootApplication
#RestController
#EnableOAuth2Client
public class SocialApplication extends WebSecurityConfigurerAdapter {
#Autowired
OAuth2ClientContext oAuth2ClientContext;
#RequestMapping({ "/user", "/me" })
public Map<String, String> user(Principal principal) {
Map<String, String> map = new LinkedHashMap<>();
map.put("name", principal.getName());
return map;
}
//TODO как это оформить на фронтенде?
#RequestMapping("/vkontakte/friends")
public Map<String,String> friends() {
OAuth2RestTemplate vkTemplate = new OAuth2RestTemplate(vk(), oAuth2ClientContext);
UserInfoTokenServices tokenServicesvk = new UserInfoTokenServices(vkResource().getUserInfoUri(), vk().getClientId());
tokenServicesvk.setRestTemplate(vkTemplate);
ObjectNode resultNode = vkTemplate.getForObject(vkResource().getUserFriendsInfoUri(), ObjectNode.class);
ArrayNode data = (ArrayNode) resultNode.get("data");
Map<String, String> map = new LinkedHashMap<>();
for (JsonNode dataNode : data) {
//TODO надо как то правильно все получить?
}
return map;
In order to fetch friends from Vkontakte, you must declare a friend object, which will contain all the fields JSON structure of a friend has.
According to documentation, every friend has an id, first name, and last name, however, the response object is a little bit more complex than we need, so you might remove what you do not need.
Assuming we need all of the attributes of the response we can come up with two objects: result and friend.
Vkontakte friend object
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class VkontakteFriend {
private Long id;
#JsonProperty("first_name")
private String firstName;
#JsonProperty("last_name")
private String lastName;
}
Generic result object
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class FriendResponse {
private Long count;
private List<VkontakteFriend> items;
}
The only thing is left is to call API and get your response mapped to Java objects.
vkTemplate.getForObject(vkResource().getUserFriendsInfoUri(), FriendResponse.class);