how to construct #service in Springboots using a payload variable - spring

I'm quite new in spring boots so I hope this is not a silly question
I have a #Service that needs to initiate a class attribute, this attribute needs a information that comes from the RestPayload in the Controller. I'm not finding the most recommend way to do that.
#RestController
public class UserController {
#Autowired
private UserService userService;
#RequestMapping("/searchUser")
public List<UserWrapper> searchUser(#RequestBody UserWrapper userWrapper) {
List<UserWrapper> returnUserWrapper = userService.findByName(userWrapper);
return returnUserWrapper;
}
}
And the service layer, I would like to be something like:
#Service
public class UserService {
private LdapTemplate ldapTemplate;
public static final String BASE_DN = "xxxxxxx";
#Value( value = "${sample.ldap.url}" )
private String ldapUrl;
#Value( value = "${sample.ldap.base}" )
private String ldapBase;
public UserService() {
}
public UserService(String dn, String password) {
LdapContextSource ctxSrc = new LdapContextSource();
System.out.println(this.ldapUrl);
ctxSrc.setUrl(ldapUrl);
ctxSrc.setBase(ldapBase);
ctxSrc.setUserDn(dn);
ctxSrc.setPassword(password);
ctxSrc.afterPropertiesSet(); // this method should be called.\
this.ldapTemplate = new LdapTemplate(ctxSrc);
}
The String dn and String password will come in the REST Payload but the other properties comes from a properties file.
Hope someone can guide me with best practices

for ldap authentication you should have a look on spring-security:
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#ldap
on the other hand you can access almost any request parameter by just injecting it via a annotation like in these examples:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestheader

Related

#PreAuthorize how do i add a parameter into the expression

Maybe somebody has an idea
I have an abstract controller providing me the endpoints i need.
In the #PreAuthorized i would execute the check if the user has the required roles.
Problem is that i have only one function and i want to check which endpoint is currently evaluated.
This is the code:
public abstract class CoreController<T> {
private final JpaRepository repository;
private final CoreService service;
public String endpoint;
private String view;
public CoreController(CoreService service, JpaRepository repository, String endpoint, String view) {
this.service=service;
this.repository = repository;
this.endpoint=endpoint;
this.view=view;
}
#PreAuthorize("#checkAccess.isAllowedToGet(#endpoint)")
#RequestMapping(method = RequestMethod.GET, value = "/get")
public ResponseEntity<CrudPage<Map<String, Object>>> get(CoreCriteria criteria) {
criteria.setView(view);
CrudPage<Map<String, Object>> data = service.getPage(criteria);
return ResponseEntity.ok(data);
}
The problem is the endpoint is always null when the function is called.
How should i change the expression to make this work.

Best Approach to load application.yml in spring boot application

I am having Spring Boot application and having application.yml with different properties and loading as below.
#Configuration
#ConfigurationProperties(prefix="applicationprops")
public class ApplicationPropHolder {
private Map<String,String> mapProperty;
private List<String> myListProperty;
//Getters & Setters
}
My Service or Controller Class in which I get this properties like below.
#Service
public ApplicationServiceImpl {
#Autowired
private ApplicationPropHolder applicationPropHolder;
public String getExtServiceInfo(){
Map<String,String> mapProperty = applicationPropHolder.getMapProperty();
String userName = mapProperty.get("user.name");
List<String> listProp = applicationPropHolder.getMyListProperty();
}
}
My application.yml
spring:
profile: dev
applicationprops:
mapProperty:
user.name: devUser
myListProperty:
- DevTestData
---
spring:
profile: stagging
applicationprops:
mapProperty:
user.name: stageUser
myListProperty:
- StageTestData
My questions are
In my Service class i am defining a variable and assigning Propertymap for every method invocation.Is it right appoach?
Is there any other better way I can get these maps without assigning local variable.
There are three easy ways you can assign the values to instance variables in your bean class.
Use the #Value annotation as follows
#Value("${applicationprops.mapProperty.user\.name}")
private String userName;
Use the #PostConstruct annotation as follows
#PostConstruct
public void fetchPropertiesAndAssignToInstanceVariables() {
Map<String, String> mapProperties = applicationPropHolder.getMapProperty();
this.userName = mapProperties.get( "user.name" );
}
Use #Autowired on a setter as follows
#Autowired
public void setApplicationPropHolder(ApplicationPropHolder propHolder) {
this.userName = propHolder.getMapProperty().get( "user.name" );
}
There may be others, but I'd say these are the most common ways.
Hope, you are code is fine.
Just use the below
#Configuration
#ConfigurationProperties(prefix="applicationprops")
public class ApplicationPropHolder {
private Map<String,String> mapProperty;
private List<String> myListProperty;
public String getUserName(){
return mapProperty.get("user.name");
}
public String getUserName(final String key){
return mapProperty.get(key);
}
}
#Service
public ApplicationServiceImpl {
#Autowired
private ApplicationPropHolder applicationPropHolder;
public String getExtServiceInfo(){
final String userName = applicationPropHolder.getUserName();
final List<String> listProp = applicationPropHolder.getMyListProperty();
}
}

How to map configuration objects to java object

I have a spring boot application which is using a spring cloud config.
How can i map a configuration element with some java object.
My config is something like this:
clients:
- id : 1
name: client 1
groups : [a,b]
- id : 2
name: client 2
groups : [a]
And my java object is:
public class ClientInfo {
private String clientId;
private List<String> profiles;
public ClientInfo(String clientId, List<String> pips) {
this.clientId = clientId;
this.profiles = pips;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public List<String> getProfiles() {
return profiles;
}
public void setProfiles(List<String> profiles) {
this.profiles = profiles;
}
}
I want to map my configuration with List
Use below code to configure configuration properties in to java Object,
#Component
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "clients")
public class ClientInfo {
private String id;
private String name;
private List<String> groups;
public String getId(){ return id;}
public String getName(){ return name;}
public List<String> getGroups(){ return groups;}
}
Check following for example http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Inject this class in another class :
#Autowired
private ClientInfo clientInfo;
The above auto wiring will not work if the class is instantiated using "new operator".
Actually I found the reason why it was not working.
All that was needed is to have another class which contains a list of ClientInfo and have #EnableConfigurationProperties and #ConfigurationProperties annotations on it. This is because "clients" in my configuration is a list. After this change we can use #Autowired annotation to inject the configuration.

How to send Java collections containing subclasses to spring controller

I'm trying to send collections to my spring MVC controller:
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#ModelAttribute("mapperList") MapperList mapperList) {
//prints {"users":null}
System.out.println(new ObjectMapper().writeValueAsString(mapperList));
return new ResponseDTO();
}
this is the code posting my users :
public ResponseDTO postUsers(ArrayList<User> users) {
ResponseDTO serverResponse = null;
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestMethod("POST");
// prints {"users":[{"property1":"x","property1":y}]}
System.out.println(objectMapper.writeValueAsString(new MapperList(users)));
objectMapper.writeValue(connection.getOutputStream(), objectMapper.writeValueAsString(new MapperList(users)));
//blabla ...
}
and this is the object containing my list :
public class MapperList implements Serializable {
private static final long serialVersionUID = 8561295813487706798L;
private ArrayList<User> users;
public MapperList() {}
public MapperList(ArrayList<User> users) {
this.setUsers(users);
}
public ArrayList<User> getUsers() {
return users;
}
public void setUsers(ArrayList<User> users) {
this.users = users;
}
}
and this is the users type to post:
public abstract class User implements Serializable {
private static final long serialVersionUID = -1811485256250922102L;
private String property1;
private String property2;
public User() {}
public User(String prop1, String prop2) {
// set properties
}
// getters and setters
}
the problem is, when I output the value of the users's array before to post it to the controller, I got the following json value :
{"users":[{"property1":"x","property1":y}]}
but in the controller, when I print what I get from the request body, I only get :
{"users":null}
I also tryed with the annotation #RequestBody instead of #ModelAttribute("mapperList") and a JSONException is displayed :
*A JSONObject text must begin with '{' at 1 [character 2 line 1]\r\n*
My array list of users contains only one user that should be displayed. I don't understand why this doesn't work...
Thanks for any help !
You can chnage your MapperList class definition as public class MapperList extends ArrayList<User>{ ..} you dont need to define any instance variable like private ArrayList users inside MapperList class. Use #Requestbody annotation. You will be able to use MapperList as a ArrayList
Try to use:
public class MapperList{
private List<User> users;
//setter and getter
//toString
}
public class User{
private String property1;
private String property2;
//getter + setter
}
json:
{"users":[{"property1":"x", "property2":"y"}]}
in controller use #RequestBody. In that case Jackson will map your json to ArrayList of users.
#ResponseStatus(HttpStatus.OK)
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList users) {
System.out.println(users);
return null;
}
no need to get objectMapper in that case. Don't forget to set content-type in request header to application/json. It required by Spring to handle #RequestBody processing.
If not working try to change MapperList:
List<User> users = new ArrayList<User>();
On the server side keep the #RequestBody annotation:
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList mapperList)
...
But this line causes problems:
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
First it converts the object to JSON and then again uses objectMapper to JSON-encode the string into output stream. Try the following instead:
connection.getOutputStream().write(
objectMapper.writeValueAsString(new MapperList(users))
.getBytes("UTF-8")
);
or directly output to stream:
objectMapper.writeValue(
connection.getOutputStream(),
new MapperList(users))
);
Zbynek gave me part of the answer. Indeed
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
doesn't work properly in my case
But moreover, my User class was an abstract class, with many type of User as subclasses. so the #RequestBody annotation couldn't work without specified the object type in the Json.
I used the following annotations on User class to make it working :
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = SubClassA.class, name = "a"),
#JsonSubTypes.Type(value = SubClassB.class, name = "b")
})
Thanks a lot for all your answers.

Relationships breaking with spring-data-neo4j 4.0.0

I've got something weird in my project and I can't see if it's may fault or not.
I'm using Spring with spring-data-neo4j (v4.0.0).
This code in my controller breaks relationships.
#RequestMapping("/initialize")
public Object initialize() {
Organization orga = new Organization();
orga.setName("WEAVERS");
this.organizationRepository.save(orga);
User user = new User();
user.setEmail("t.rignoux#gmail.com");
user.setFirst_name("Thierno");
user.setLast_name("Rignoux");
user.setLogin("317");
user.setOrganization(orga);
this.userRepository.save(user);
User user2 = new User();
user2.setEmail("petitenessie#gmail.com");
user2.setFirst_name("Eléonore");
user2.setLast_name("Klein");
user2.setLogin("nessie");
user2.setOrganization(orga);
this.userRepository.save(user2);
Project project = new Project();
project.setName("PROJET 1");
project.setOrganization(orga);
project.setUser(user);
this.projectRepository.save(project);
Project project2 = new Project();
project2.setName("PROJET 2");
project2.setOrganization(orga);
project2.setUser(user2);
this.projectRepository.save(project2);
return orga;
}
As you can see on this graph:
The relation between ORGANIZATION and USER1 has been severed when I created USER2.
Broken relationships is something I see everywhere in my application... I don't understand!
neo4j configuration
#EnableTransactionManagement
#Import(RepositoryRestMvcConfiguration.class)
#EnableScheduling
#EnableAutoConfiguration
#ComponentScan(basePackages = {"fr.weavers.loom"})
#Configuration
#EnableNeo4jRepositories(basePackages = "fr.weavers.loom.repositories")
public class LoomNeo4jConfiguration extends Neo4jConfiguration {
public static final String URL = System.getenv("NEO4J_URL") != null ? System.getenv("NEO4J_URL") : "http://localhost:7474";
#Override
public Neo4jServer neo4jServer() {
return new RemoteServer(URL,"neo4j","loomREST2016");
}
#Override
public SessionFactory getSessionFactory() {
return new SessionFactory("fr.weavers.loom.domain");
}
}
Organization Domain :
public class Organization extends Node {
#GraphId
Long id;
String name;
#Relationship(type = "SET_UP", direction = Relationship.OUTGOING)
Set<SET_UP> projects;
#Relationship(type = "WORK_FOR", direction = Relationship.INCOMING)
Set<WORK_FOR> users;
[...]
WORK_FOR Domain :
public class WORK_FOR extends Relationship {
#GraphId
private Long relationshipId;
#StartNode
public User user;
#EndNode
public Organization organization;
public WORK_FOR() {
super();
}
}
User Domain:
public class User extends Node {
#GraphId
Long id;
String login;
#JsonIgnore
String password;
String first_name;
String last_name;
String email;
#Relationship(type = "WORK_FOR")
WORK_FOR workFor;
I looked everywhere and I can't find anything to help me...
Thank you
In your initialisation request you make several repository calls to construct the database. Each of these calls will construct a new Session, effectively clearing out information from the previous one because the Spring config defaults to Session-per-request. This is most likely the reason existing relationships are being deleted.
If you add the following bean definition to your config, I believe the problem should be resolved.
#Override
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
Please refer to the documentation here for more information about Session scope.
Please annotate the incoming relationship on your Node class:
#Relationship(type = "WORK_FOR", Direction = Relationship.INCOMING)
WORK_FOR workFor;
As per the documentation, all INCOMING relationships must be fully annotated - the default is OUTGOING.

Resources