how to support Polymorphism with RESTeasy Client proxy? - spring-mvc

suppose this JAX-RS method :
#GET
#Path("/{id}")
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Employee get(#PathParam("id") Long id) {
return myService.findbyId(id);
}
With the following POJO:
#XmlRootElement
public class Employee {
Integer id;
String name; (getters;setters etc...)
}
#XmlRootElement(name="employee")
public class SepcialEmployee extends Employee {
Skill skill; (getters;setters etc...)
}
#XmlRootElement(name="employee")
public class Manager extends Employee {
String headOffice; (getters;setters etc...)
}
This works fine with RESTeasy/spring-MVC integration. And if I call the method from a web browser; I can get the following answer for i.e.:
<employee Id="17">
<name>Marc</name>
<headOffice>accounting</headOffice>
</employee>
But if I use the RESTeasy Client Framework for my unit test. the client proxy generated unmarsalles only the Employee Parent class and I loose the child informations (Manager.headOffice or SepcialEmployee.Skill). Below an extract of my Junit test:
public class Test {
#Path("empl")
public interface EmpProxy {
#GET
#Produces(MediaType.APPLICATION_XML)
Employee getEmployee(#ClientURI String uri);
}
private static TJWSEmbeddedSpringMVCServer server;
public static final String host = "http://localhost:8080/";
public static final int port = 8080;
private static EmpProxy proxy;
#BeforeClass
public static void setup() {
server = new TJWSEmbeddedSpringMVCServer("classpath:test-dispatcher-servlet.xml", port);
server.start();
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(host);
proxy = target.proxy(EmpProxy.class);
}
#Test
public void test(){
String url = host+"/empl/17";
Employee employee = proxy.getEmployee(url);
System.out.println(employee);
}
}

Related

ASP.NET Core 3 Dependency Injection - Data Access / Business Layer Class Library

Very new to DI and concepts so I'm struggling to find a solution to the following:
We have a Web Project (MVC, Core 3) and a Class Library (for all the business and data layers). We are trying to have a DBContext Class in the Class Library to handle all the DB connections (using connection string). We can DI into this DBContext the IConfiguration so we can extract the connection string from this and place into a local readonly string. We have a method to return the SQL Connection using this connection string.
The issue is when we are in a business class, we need to access the DBContext class to obtain a SQL Connection object. We cannot create a "new" DBContext as we do not have the IConfigration in the other business classes.
DBContext class library:
public class DBContext
{
private readonly string _connectionString;
private readonly IConfiguration _configuration;
public DBContext(IConfiguration configuration)
{
_configuration = configuration;
_connectionString = configuration.GetConnectionString("db");
}
public SqlConnection Connection()
{
return new System.Data.SqlClient.SqlConnection(_connectionString);
}
}
So the problem lies when we look at the Customer class in the Class Library:
Customer Class:
public class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public Customer(int customerId)
{
//load customer from the db from the id
using (IDbConnection db = new DBContext().Connection())
{
//call SQL Stored Procedure here ....
}
}
}
We are unable to create a "new" DBContext to access the connection, as in the Customer Class we don't have the IConfiguration object to pass to the constructor.
How do we achieve this the "correct" way?
Is it as bad as having to DI the IConfiguration object into every single class library constructor e.g. Customer from all the web controllers, so we can pass it over to the DBContext? As this seems long winded.
Sorry if this is very basic DI stuff but just struggling to find a good example on how to do this stuff.
Thanks in advance,
Ro
public class Customer
{
private readonly ApplicationDbContext _context;
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public Customer(ApplicationDbContext context, int customerId)
{
_context = context; //use _context to reference the db context.
//do stuff
}
}
And in Startup.cs -> ConfigureServices() method:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DevDb")));
Edit for Dapper:
In appsettings.json:
"ConnectionStrings": {
"DefaultConnection": "<connection string here>"
}
Then add a class called ConnectionString in the solution. We will use this class to hold the connection string value from the configuration file and use it in our classes via dependency injection.
public sealed class ConnectionString
{
public ConnectionString(string value) => Value = value;
public string Value { get; }
}
Then Register the configuration in the ASP.NET Core dependency injection container in Startup.cs
var connectionString = new ConnectionString(Configuration.GetConnectionString("DefaultConnection"));
services.AddSingleton(connectionString);
Then add your repository class:
using Dapper;
public class MovieRepository
{
private readonly ConnectionString _connectionString;
public MovieRepository(ConnectionString connectionString)
{
_connectionString = connectionString;
}
public async Task<IEnumerable<MovieModel>> GetAllMovies()
{
const string query = #"SELECT m.Id, m.Name,d.Name AS DirectorName, m.ReleaseYear
FROM Movies m
INNER JOIN Directors d
ON m.DirectorId = d.Id";
using (var conn = new SqlConnection(_connectionString.Value))
{
var result = await conn.QueryAsync<MovieModel>(query);
return result;
}
}
}
Then Register the Repository class in you DI container. Add the following code to ConfigureServices method.
services.AddScoped<MovieRepository>();
Add the controller class MoviesController.cs and write an action method to fetch all movies using this MovieRepository.
[ApiController]
public class MoviesController : ControllerBase
{
private readonly MovieRepository _movieRepository;
public MoviesController(MovieRepository movieRepository)
{
_movieRepository = movieRepository;
}
[HttpGet("api/movies")]
public async Task<IActionResult> GetMovies()
{
return Ok(await _movieRepository.GetAllMovies());
}
}
In this example, your ApplicationDbContext is equivalent to the movie repository. Answer from: https://www.c-sharpcorner.com/article/using-dapper-for-data-access-in-asp-net-core-applications/

Adding server side dynamic validations in spring boot

I am using Spring Boot 2. I want to add certain dynamic validations at server side which should be executed in POST REST call. Can these validations be added in form of annotations at parameter level of POST method call?
Below code will help you to achieve server side validation.
Pojo class :
public class Data {
#NotNull
private final String someStringValue;
#Min(1)
private final int someIntValue;
#JsonCreator
public Data(#JsonProperty("someStringValue") String someStringValue, #JsonProperty("someIntValue") int someIntValue) {
this.someStringValue = someStringValue;
this.someIntValue = someIntValue;
}
public String getSomeStringValue() {
return someStringValue;
}
public int getSomeIntValue() {
return someIntValue;
}
For the validation we need a custom class containing the logic:
#Component
public class StringValueValidator {
public void validate(String language, Data data, Errors errors) {
if (!"de-DE".equals(language)) {
if (data.getSomeStringValue().length() > 140) {
errors.reject("someStringValue");
}
}
}
}
controller method :
#RequestMapping(value = "/validation", method = RequestMethod.POST)
public ResponseEntity<?> acceptData(#Valid #RequestBody Data data, Errors errors,
#RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String language) {
stringValueValidator.validate(language, data, errors);
if (errors.hasErrors()) {
return new ResponseEntity<>(createErrorString(errors), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.OK);
}
Refer this : https://blog.codecentric.de/en/2017/11/dynamic-validation-spring-boot-validation/
Here is how you can achieve to defining validations in RequestBody you are receiving from client side.
Define your POJO you will receive from client side.
public class Employee implements Serializable {
private Long id;
#NotNull(message = "Name should not be null")
#NotBlank(message = "Name should be not empty")
#Size(min = 1, max = 255, message = "Name allowed max 255 characters")
private String name;
Now in your controller use #Valid annotation for #RequestBody like below.
public ResponseEntity<?> createEmployee(#Valid #RequestBody Employee employee)

Mongo Java Connectivity - Only Insert once

I have a Mongo - Java MVC Spring 4 connectivity. My insert operations work only once, they don't do a second insert in the collection. What could be the problem?
Here's my code.
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection="subject")
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE)
private int id;
private String name;
private String email;
private String address;
private String telephone;
strong text
...
public class EmployeeDAOImpl implements EmployeeDAO {
MongoTemplate mongoTemplate;
public MongoTemplate getMongoTemplate() {
return mongoTemplate;
}
public void setMongoTemplate(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
#Override
public void addEmployee(Employee employee) {
mongoTemplate.save(employee);;
}
#Override
public List<Employee> getAllEmployees() {
// TODO Auto-generated method stub
return mongoTemplate.findAll(Employee.class);
}
#GeneratedValue(strategy=GenerationType.SEQUENCE) annotation is for JPA and not for Mongo.
Make sure that you import the #Id from the mongo package and ID should be auto generated by Mongo.
The first insert works because int has default value of 0 and the second time it tries to insert with the same key.
if you want to have custom ids generated, here is a great tutorial for that: https://www.baeldung.com/spring-boot-mongodb-auto-generated-field

Curiosities in deserializing collections with gson 2

I have these classes
public class Application {
public String name;
public String ico;
public List<MenuStruct> menu =new ArrayList<MenuStruct>();
//Constructor
public Application() { }
}
public class MenuStruct {
public String id;
public String type;
public String parent;
public String name;
public String secId;
//Constructor
public MenuStruct() {}
}
If I try to deserialize a collection directly in this way:
ApplicationManager apm= new ApplicationManager();
s="[ {\"name\":\"reg_salida\" , \"ico\":\"document-open-2-32x32.ico\" }]";
apm.apps=(new Gson()).fromJson(s,apm.apps.getClass() );
for (Application ap:apm.apps){
System.out.println(ap.name); //gets error here
}
I get a java.lang.ClassCastException.
But if I try to deserialize its containig class ApplicationManager it does not fail.
s="{ \"apps\": [ {\"name\":\"reg_salida\" , \"ico\":\"document-open-2-32x32.ico\" }]}";
ApplicationManager apm=(new Gson()).fromJson(s,ApplicationManager.class);
for (Application ap:apm.apps){
System.out.println(ap.name); // now no errors here! and shows reg_salida
}
Is this a bug of gson 2.2.4? or maybe I am doing something not correct?
Eduard.
You have to provide full definition of property class. Your example should looks like that:
manager.apps = gson.fromJson(json, new TypeToken<List<Application>>() {}.getType());

IOC with multiple databases that use same interface (StructureMap or any other DI Framework)

We've been experimenting with StructureMap, and I'm having trouble grasping how to handle situations where a single interface has multiple implementations. The code below shows an example where we have two databases that are both accessible from a single service.
public class SomeController : Controller
{
private ISomeService _service;
private IClientRepository _repository;
protected IContext _masterContext;
protected IContext _clientContext;
public SomeController(ISomeService service, ISomeRepository repository
, IContext masterCon, IContext clientCon)
{
_service = service;
_repository = repository;
_masterContext = masterCon;
_clientContext = clientCon;
}
}
public class SomeService : ISomeService
{
private IContext _masterContext;
private IContext _clientContext;
public SomeService(IContext masterContext, IContext clientContext)
{
masterContext = _masterContext;
clientContext = _clientContext;
}
}
public class ClientRepository : IClientRepository
{
private IContext _clientContext;
public ClientRepository(IContext clientContext)
{
_clientContext = clientContext;
}
}
public class MasterContext : IContext
{
public MasterContext(String connString)
//<snip, snip> implement 3rd party data context
}
public class ClientContext : IContext
{
public ClientContext(String connString)
//<snip, snip> implement 3rd party data context
}
StructureMap worked GREAT when we had a single context (database), but how do I tell it how to resolve the 2nd? Note: in most situations we wouldn't have a service handling 2 databases (but may have a controller handling 2 connections, i.e. 2 repositories accessing 2 different databases), but it still doesn't seem to make it easier.
I'm half ready to just give up on using an IoC framework and go back to poor man's DI.
Is it not possible to have an IClientContext and an IMasterContext, possibly inheriting from IContext. My feeling is that the code would be doing one of two very different things depending on whether you were talking to the 'Master' or 'Client' database.
In Unity you can have named registrations, allowing you to effectively register more than a class for a given interface. So you could do (typing by heart, check the actual Unity documentation if interested):
container.RegisterType<IContext, MasterContext>("Master");
container.RegisterType<IContext, ClientContext>("Client");
and then the constructor for SomeService would be:
public SomeService(
[Dependency("Master")]IContext masterContext,
[Dependency("Client")]IContext clientContext)
{
//...
}
The drawback is that in this way your service class is no longer independent of the DI framework used, but depending on the project that may be ok.
This can be a little difficult if you're relying on StructureMap to resolve the dependencies automatically. The first solution (and what I'd err towards) is to make use of marker interfaces like Richard mentions in his answer then just register them. You can then explicitly specify whether you want your client or master context there.
The second way is to make use of named registrations, then specify the constructor params explicitly.
ForRequestedType<IContext>().AddInstances(
i => {
i.OfConcreteType<ClientContext>().WithName("Client");
i.OfConcreteType<MasterContext>().WithName("Master");
});
ForRequestedType<SomeController>().TheDefault.Is.ConstructedBy(
i => new SomeController(i.GetInstance<ISomeService>(),
i.GetInstance<IClientRepository>(),
i.GetInstance<IContext>("Master"),
i.GetInstance<IContext>("Client")));
Not particularly nice but it does the job and ultimately if it's only in one or two places it might be OK.
If you want to resolve differently on namespace / assembly you could try something like this:-
ForRequestedType<IContext>().AddInstances(
i => {
i.OfConcreteType<ClientContext>().WithName("Client");
i.OfConcreteType<MasterContext>().WithName("Master");
}).TheDefault.Is.Conditional(c => {
c.If(con => con.ParentType.Namespace.EndsWith("Client"))
.ThenIt.Is.TheInstanceNamed("Client");
c.If(con => con.ParentType.Namespace.EndsWith("Master"))
.ThenIt.Is.TheInstanceNamed("Master");
c.TheDefault.Is.OfConcreteType<ClientContext>();
});
Where the predicate on ParentType can refer to Assembly (or whatever you want really)
In case someone stumble in this problem, you can achieve it using factory pattern.
Service extension
public static class ServiceFactoryExtensions
{
public static void RegisterSqlFactory(this IServiceCollection serviceCollection)
{
serviceCollection.Configure<MsSqlOption>(option => option.ConnectionString = "Mssql connection string");
serviceCollection.Configure<MySqlOption>(option => option.ConnectionString = "Mysql connection string");
serviceCollection.Configure<PostgreOption>(option => option.ConnectionString = "Postgrel connection string");
serviceCollection.AddSingleton<ISqlDatabase, MsSql>();
serviceCollection.AddSingleton<ISqlDatabase, Postgre>();
serviceCollection.AddSingleton<ISqlDatabase, MySql>();
serviceCollection.AddSingleton<Func<IEnumerable<ISqlDatabase>>>(serviceProvider => () => serviceProvider.GetService<IEnumerable<ISqlDatabase>>());
serviceCollection.AddSingleton<ISqlDatabaseFactory, SqlDatabaseFactory>();
}
}
Factory class
public class SqlDatabaseFactory : ISqlDatabaseFactory
{
private readonly Func<IEnumerable<ISqlDatabase>> _factory;
public SqlDatabaseFactory(Func<IEnumerable<ISqlDatabase>> factory)
{
_factory = factory;
}
public ISqlDatabase CreateSql(SqlType sqlType)
{
var databases = _factory();
var sqlDatabase = databases.FirstOrDefault(x => x.DatabaseName == sqlType);
if (sqlDatabase == null)
throw new NotImplementedException($"Sql type {nameof(sqlType)} is not implemented");
return sqlDatabase;
}
}
Sql classes
public class MsSql : ISqlDatabase
{
public SqlType DatabaseName => SqlType.MsSql;
public string Connecionstring { get; private set; }
public MsSql(IOptions<MsSqlOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public class Postgre : ISqlDatabase
{
public SqlType DatabaseName => SqlType.Postgre;
public string Connecionstring { get; private set; }
public Postgre(IOptions<PostgreOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public class MySql : ISqlDatabase
{
public SqlType DatabaseName => SqlType.MySql;
public string Connecionstring { get; private set; }
public MySql(IOptions<MySqlOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public interface ISqlDatabase
{
string Connecionstring { get; }
SqlType DatabaseName { get; }
}
public enum SqlType
{
MsSql,
Postgre,
MySql
}
Usage
internal class Program
{
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.RegisterSqlFactory();
var provider = serviceCollection.BuildServiceProvider();
var sqlFactory = provider.GetService<ISqlDatabaseFactory>();
var mySql = sqlFactory.CreateSql(SqlType.MySql);
var msSql = sqlFactory.CreateSql(SqlType.MsSql);
var postgre = sqlFactory.CreateSql(SqlType.Postgre);
Console.WriteLine($"Database Type : {mySql.DatabaseName}, Connectionstring: {mySql.Connecionstring}");
Console.WriteLine($"Database Type : {msSql.DatabaseName}, Connectionstring: {msSql.Connecionstring}");
Console.WriteLine($"Database Type : {postgre.DatabaseName}, Connectionstring: {postgre.Connecionstring}");
Console.ReadKey();
}
}
Output
Dependencies:
.Net Core 3.1
Microsoft.Extensions.DependencyInjection;
Microsoft.Extensions.Options;
System
System.Collections.Generic
System.Linq;

Resources