I have a service call that returns a JSON response which is then passed through a data manager that transforms the data if service is success or creates an error body if the call is a failure.
The data manager is written in kotlin and the particular line of
code i am interested in is this
val mutableList = mutableListOf<Address>()
return Result.error(errorTransformation(serviceErrors, mutableList))
My errorTransformation class is basically an Exception call and this is written java. The constructor for the exception class is
ExceptionClass(ServiceErrors serviceError ,List<Address> address){
// initiialize fields here
}
Now When i try to initialize my exception class it says appropriate constructor is found and it is showing me a suggestion to generate one with syntax
ExceptionClass(ServiceErrors serviceError ,List<? extends Address> address){
// initiialize fields here
}
Why is this happening? I only want List<Address>, not List<? extends Address>.
It's kotlin specific behavior to implicitly use List<? extends Address> instead of List<Address>. You can force kotlin generate exactly what you need using #JvmSuppressWildcards annotation
val mutableList = mutableListOf<#JvmSuppressWildcards Address>()
Related
I'm using kotlin to store in a database a class from a library. The problem is that this class, haven't got a constructor with no arguments(It is a Java class). When I retrieve the object from the database, I get the following error, as It has no constructor:
java.lang.NoSuchMethodException: org.springframework.security.oauth2.core.OAuth2AccessToken.<init>()
The only solutions I think It will solve the problem, are the following:
Change the class where I retrieve the object to Java.
Store a different object instead of org.springframework.security.oauth2.core.OAuth2AccessToken class
Any more thoughts on how to solve this problem?
This is my class in the database:
#Document(collection = "authorizedClient")
data class AuthorizedClientDatabase(
#Id
var id: ObjectId = ObjectId.get(),
var name: String? = null,
var clientRegistration: ClientRegistration,
var accessToken: OAuth2AccessToken,
var refreshToken: OAuth2RefreshToken? = null
)
This is the repository class:
#Repository
interface AuthorizedClientDatabaseRepository : MongoRepository<AuthorizedClientDatabase, ObjectId> {
}
This is the OAuth2AccessToken
And I'm simply making a:
authorizedClientDatabaseRepository.findById(...)
OAuth2AccessToken class does not have a non-argument constructor that you are attempting to call. You need to change your code to use one of the two existing constructors:
public OAuth2AccessToken(TokenType tokenType, String tokenValue,
Instant issuedAt, Instant expiresAt) {
// ...
}
or
public OAuth2AccessToken(TokenType tokenType, String tokenValue,
Instant issuedAt, Instant expiresAt, Set<String> scopes) {
// ...
}
I finally changed the OAuth2AccessToken class and created a custom one:
data class DatabaseOauth2AccessToken(
val tokenValue: String,
val issuedAt: Instant?,
val expiredAt: Instant?,
val scopes: MutableSet<String>
)
AFAIK, this is the most viable solution I have found.
In addition to Karol Dowbecki's answer; if you don't specify a constructor either way all classes provide you with an empty constructor (no params) and no body in it.
Your problem could be one of these:
The empty constructor is private hence not visible to the bit of code that is trying to create an instance
It just has not an empty constructor. There are already other constructors but no "empty" constructor specified. This could be what Karol Dowbecki mentions
It is specified but is private hence we're back to point 1.
A data class should have no effect on this. Data classes just take care of wrapping properties with a backing field and providing you with getters and setters Thanks Alexey for correcting. Kotlin does that with all properties. Besides that, they write the implementation of the toString, equals and hashCode methods and adds a nice method to generate copies of the same object called copy
Suppose I have a base class (which i'm simplifying):
public class GenericException extends Exception {
private Map<String,Object> map;
//...
public GenericException(String message, String[] params, Object... values) {
super(message);
map = createMap(params, values);
}
//... other stuff
public String getType() {
getClass().getName();
}
}
This class may be extended by clients but there is no point in adding members to any of its sub-classes, because the class and its sub-classes, when thrown, will result in some Json streamed to some client, containing only the map, the type, and the message
A typical sub-class may be something like
public class Exception1 extends GenericException {
private String message = "something";
private String params = new String[] {"foo", "bar"};
//...
public Exception1(Object... values) {
super(message, params, values);
}
//... other stuff
}
At some other point in the code there is a need to take the Json representation of any GenericException (or its sub-class) and create an instance of that class. The type attribute may be used to figure out which class needs to be instantiated, and the map is in the Json representation so the params and values can be obtained.
If every sub-class could be forced to implement a constructor having the parameters
String message, String[] params, Object... values
then it would be easy.
But every sub-classs, although eventually it must call the constructor in GenericException, may have various unknown constructors.
I'm looking for some magic that would allow me to inject such a [virtual] constructor into every sub-class of GenericException,
so that the code that needs to create the exeption from Json
can call this "virtual" constructor perhaps by reflection...
Is it possible to create this magic by somehow annotating the class and doing some Spring Aspect annotation? (Spring is used in this project))
Or is there some other way to do it?
Additional information added 10/16/2018
Thanks to all the commenters. I guess I need to add more information:
1) I'm using Spring Boot
2) i don't want to add setters. I think exceptions should be immutable. Let's not argue about that.
3) sure there could be directive that you must implement some additional constructor in every extension of the base class. But i prefer not to do that.
4) I know I need to use AspectJ. But how is that done?
So think about it this way: people are writing sub-classes of GenericExceptions and i don't have any control over their code. I own GenericException and i am responsibile for some infrastructure code which is supposed to reconstruct any sub-class of GenericExceptions which is in the classpath but does not have any setters.
I've got a Kotlin class, similar to
data open class MyDto (
var property: String? = null
// ...
)
and a Java class extending this class, similar to
class MySpecificDto extends MyDto {
private String field;
// getter/setter for "field"
public MySpecificDto(final MyDto prototype)
{
super(prototype);
}
}
What is missing in Kotlin's DTO for the "super(prototype)" statement to compile?
MyDto's constructor takes a single parameter of type String, and you are trying to pass it a MyDto.
I think you are looking for --
super(prototype.getProperty());
Data classes seem a like logical base for a hierarchy of DTOs. Unfortunately, they do not play well with inheritance, so doing so is not a good idea. See this answer.
Update to address comment --
For a Kotlin side solution, you need to remember Kotlin classes only allow for a single constructor. For data classes, the format of that constructor is already defined, so you cannot just pass an object and have it work, or define a different constructor. Also, as noted by #bashor in comment to your original question, there is no copy constructor. You can, however, create a separate function to initialize your object if you want --
data open class MyDto (var property: String? = null //...) {
fun init(dto: MyDto) {
property = dto.property
//... rest of the properties
}
}
and the in your Java constructor call init instead of super.
public class MySpecificDto extends MyDto {
private String field;
public MySpecificDto(final MyDto prototype)
{
init(prototype);
}
}
The caveat on this solution is that your data class must provide default values for all of its properties because there is an implicit call to the constructor with zero parameters.
I have two generic classes
class Value<T>{...}
class Parameter<T>{...}
And i want to call a method from another class (Params)
public <T> void put(Parameter<T> key, Value<T> value) {
parameters.put(key, value);
}
And from my main class i want to call it with two objects Value and Parameter but with the Type in this way:
Value<Integer> v1 = new Value<Integer>(2);
Parameter<Integer> p1 = new Parameter<Integer>(3);
Params params = new Params();
params.put(p1,v1);
And i receive this error from Eclipse:
The method put(Parameter<T>, Value<T>) in the type Parameters is not applicable for the arguments (Parameter<Integer>, Value<Integer>)
Any hint of how can i call this method without having this error? This classes were not developed by me, so I'm trying to call them without success.
The compiler cannot derive what your class is, so you have to give it a hint:
params.<Integer>put(p1,v1);
Wouldn't it make sense to make the Params class generic?
I have a Web Service created in Java (1.6), with metro (2.0), using maven, under Tomcat 6.
In all web methods the return type is a generic class:
public class WsResult<T> {
protected T result; // the actual result
protected Code requestState; // 0K, or some error code if needed
protected String message; // if error, instead of result, insert a message
}
For example:
public WsResult<OtherClass> someMethod(...);
public WsResult<Foo> someMethod_2(...);
And in client:
MyServiceService service = new MyServiceService();
MyService port = service.getMyServicePort();
WsResult result = port.someMethod(...);
OtherClass oc = (OtherClass) result.getResult();
WsResult res = port.someMethod_2(...);
Foo o = (Foo) res.getResult();
In some web methods it is working.
But when the result is a class with have a List<? class> attribute, it fails to unmarshal.
This project is part of a biggest one. So for test purposes I created a new one, simpler, just the project, with the same data model, and copy one of the web methods, in this case it worked, and after unmarshal, I had a result that i could cast to the expected type.
What could be happening?
EDIT:
The answer is a solution yes, but generates a getter for each type added to the field declaration.
Is there a better way?
I'm not really sure if I fully understand your problem, but to me it seems you expect a little too much from JAXB here. Your WsResult is generic in the unrestricted parameter T, which means at runtime there's nothing left but an Object reference for JAXB to play with.
What JAXB really needs to deal with such a situation is, loosely speaking, a hint on which class to instantiate to fill the result field. To fill this in you should either
create concrete subclasses of WsResult (like, following your example, class OtherClassResult extends WsResult<OtherClass> -- when you throw the OtherClassResult at JAXB, it will know that result needs to be an instance of OtherClass and has a chance to act accordingly or
annotate the result field with #XmlElements, like this:
#XmlElements({
#XmlElement(name = "text", type = String.class), // add more elems here
#XmlElement(name = "other", type = OtherClass.class)})
protected Object result;