trying to set some parameters in the AuthenticationManager of SpringBootSecurity by getting values from application.properties, but the values are only the one set by default, and not the one in the application.properties file
Have used #Value in other places of my app without problem, but in this class somenthing is wrong...
whatever I set in application.properties, the values are always the default ones.
e.g refreshTokenExpiredDays should be 4 (see applicationproperties file below) but in fact it is 1
import org.springframework.beans.factory.annotation.Value
class ApplicationAuthenticationFilters(
authenticationManager: AuthenticationManager
):UsernamePasswordAuthenticationFilter(authenticationManager) {
#Value("\${security-json-token-secret}")
private val jsonTokenSecret: String = "secret"
#Value("\${security-access-token-expired-mns}")
private val accessTokenExpiredMns: Int = 10
#Value("\${security-refresh-token-expired-days}")
private val refreshTokenExpiredDays: Int = 1
#Value("\${security-tokens-in-header}")
private val tokensInHeader: Boolean=false
...
...}
application.properties
cors-origin-patterns=http://localhost:3000,https://localhost,http://localhost:8080
security-json-token-secret=secret
security-access-token-expired-mns=20
security-refresh-token-expired-days=4
security-tokens-in-header=true
[EDIT] wondering why someone set -1 to my question...
BTW, yes, this filter class is called when overriding the configure function in the WebSecurityConfigurerAdapter
override fun configure(http: HttpSecurity) {
val applicationAuthenticationFilter:ApplicationAuthenticationFilters = ApplicationAuthenticationFilters(authenticationManagerBean())
applicationAuthenticationFilter.setFilterProcessesUrl("/auth/login")
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http.authorizeRequests().antMatchers("/auth/login/**", "/auth/token/refresh/**").permitAll();
http.authorizeRequests().anyRequest().authenticated()
// filtre ici pour gérer la JWT vai authentificationManager
http.addFilter(applicationAuthenticationFilter)
}
[EDIT 2] My solution
Finaly have created a data class that I inject in all constructors that require a variable from application.properties
#Component
data class EnvVariables(
#Value("\${security-json-token-secret}")
val jsonTokenSecret: String = "secret",
#Value("\${security-access-token-expired-mns}")
val accessTokenExpiredMns: Int = 10,
#Value("\${security-refresh-token-expired-days}")
val refreshTokenExpiredDays: Int = 1,
#Value("\${security-tokens-in-header}")
val tokensInHeader: Boolean = false
)
You can do the following:
#Value("\${security-json-token-secret:secret}")
lateinit var jsonTokenSecret: String
#Value("\${security-access-token-expired-mns:10}")
lateinit var accessTokenExpiredMns: Int
#Value("\${security-refresh-token-expired-days:1}")
lateinit var refreshTokenExpiredDays: Int
#Value("\${security-tokens-in-header: false}")
lateinit var tokensInHeader: Boolean
Note: Your class (filter or otherwise) will need to be an #Bean or #Component in order to have values injected into them. In your [EDIT] it appears you are constructing it manually, in which case your properties will not be handled by Spring.
Additionally, other techniques exist instead of #Value, such as using #ConfigurationProperties.
Related
I have scenario where in I have a "Lookup Table" class that holds getters and setters for multiple class types. As I'm interfacing with a database, I need to provide a way to provide a result boolean and then the class instance which was requested.
For example. Say I have an AssetStatus, StockItemStatus and NominalCode class. I would have to write the following data class for each:
data class LookupResult(
val wasSuccessful: Boolean = false,
val resultClass: AssetStatus? = null,
)
// or
data class LookupResult(
val wasSuccessful: Boolean = false,
val resultClass: StockItemStatus? = null,
)
// or
data class LookupResult(
val wasSuccessful: Boolean = false,
val resultClass: NominalCode? = null,
)
Ideally I don't want to have to repeat myself so I was wondering if I could write one data class (or normal class?) which is able to return one of my multiple Lookup classes?
Initially I thought it would have needed to be Any but after looking into this, that might not be the best case for what I want.
So is there a way of sticking to writing once but not repeating? Or is it something I have to do?
Edit:-
All of my class types would have the following structure (note: I'm using Spring Boot as back end) :
#Entity
#Table(name = "lookup_asset_status")
data class AssetStatus(
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "asset_status_id")
val id: Long? = null,
#Column(name = "asset_status_name")
val name: String = "",
)
...
// Repeat for each entity type
...
If I understand correctly, you want something like this:
data class LookupResult<T>(
val wasSuccessful: Boolean = false,
val resultClass: T? = null,
)
Each of the classes would be written as LookupResult<AssetStatus>, LookupResult<StockItemStatus> and LookupResult<NominalCode>.
If your method needs to be able to return any of those three classes, then it should be declared to return LookupResult<*>. Note that you can only access the members of Any when you access the resultClass of a LookupResult<*>, because you don't know which exact look up result it is.
I have the next peace of code
#Test
fun `simple test`() {
val objectMapper = ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.registerModule(KotlinModule())
val value = objectMapper.writeValueAsString(MyClass(myField1 = "something", myField2 = "something2"))
assertNotNull(value)
}
data class MyClass (
val myField1: String? = null,
#JsonProperty("my_field_2")
val myField2: String? = null,
)
the result of deserialization is next
{"my_field1":"something","my_field_2":"something2"}
Is it possible to configure objectMapper to automatically populate _ value, before digits in object property names, without specifying it in #JsonProperty?
Yes, this is possible using a PropertyNamingStrategy:
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
Note that you named your snake-case fields inconsistently, because there is my_field1 without a _ before the digit, and my_field_2 with a _ before the digit. The configuration above using PropertyNamingStrategies.SNAKE_CASE works fine for the first naming (like in my_field1).
If you want to use the second naming (like in my_field_2), then you would have to write your own naming strategy like this:
class MySnakeCaseStrategy : NamingBase() {
override fun translate(input: String?): String? =
if (input == null) null
else "([A-Z]+|[0-9]+)".toRegex().replace(input) { "_${it.groupValues[1]}".lowercase() }
}
That naming strategy can then be used to configure your object-mapper:
objectMapper.setPropertyNamingStrategy(MySnakeCaseStrategy())
I do not know if and how it would be possible to support both naming strategies at the same time.
I don't know how to get the string in readable format in my app. My code is:
val allergyList = recipeItem.allergies
allergyList.joinToString()
var allergyString: String = ""
for (allergy in allergyList) {
allergyList[1]
allergyString += " ${allergy}"
println(allergy.toString())
}
holder.recipeSearchPageAllergies.text = allergyString
When I print this I get the allergy string memory space?
Result for each one is something like this:
Allergy#4e8f238
How do I 'decode' it into something readable for a human? It should say 'nut allergy'.
you have some options. If you have the control over the Allergy source code,
you could override toString method:
class Allergy(val name: String) {
override fun toString(): String = "Allergy[name=${name}]"
}
println(Allergy("flowers"))
// Allergy[name=flowers]
also, you can make a data class of it. Data class has sane toString by default. It also has a few nice perks, like by default equals/hashCode generation, and deconstruction to components, allowing you to use it in destructing:
data class Allergy(val name: String)
println(Allergy("peanuts"))
// Allergy(name=peanuts)
otherwise, if you can't modify the source of the Allregy, you can make up an extension method for that:
class Allergy(val name: String)
fun Allergy.readable() = "Allergy[name=${name}]"
println(Allergy("cats").readable())
// Allergy[name=cats]
in your case, you could also make an extension method for collections of allergies to have the format you need:
fun Collection<Allergy>.readable() = joinToString { "Allergy[name=${it.name}]" }
println(
listOf(Allergy("cats"), Allergy("peanuts"), Allergy("flowers")).readable()
)
// Allergy[name=cats], Allergy[name=peanuts], Allergy[name=flowers]
// in your case:
holder.recipeSearchPageAllergies.text = recipeItem.allergies.readable()
// or just
holder.recipeSearchPageAllergies.text = recipeItem.allergies.joinToString { "Allergy[name=${it.name}]" }
You can make it simplier:
val allergiesStr = recipeItem.allergies.map { allergy ->
// your allergy name from allergy variable
}.joinToString(separator = " ")
I'd like to calculate some properties of my domain objects at DB level using neo4j and return the read-only results. In JPA one can achieve this via #Formula annotation over field of domain object entity:
#Formula("(select avg(f.rating) from Feedback f where f.offer_id = offer_id)")
private Double rating;
What should one do to achieve the same behavior in Spring data neo4j? I wrote a Cypher query, but don't know where to use it.
A similar outcome can be achieved using #QueryResult
Create a class with fields to hold return data.
Annotate it with #QueryResult
Example: (in Kotlin, which is what I had on hand)
#QueryResult
open class Principal constructor(applicationToken: String,
profileId: String,
stageName: String,
showMeLaterDays: Float,
roles: Array<Role>)
{
var applicationToken: String
var profileId: String
var stageName: String
var showMeLaterDays: Float
#Convert(RoleArrayAttributeConverter::class)
var roles: Array<Role>
init
{
this.applicationToken = applicationToken
this.profileId = profileId
this.stageName = stageName
this.showMeLaterDays = showMeLaterDays
this.roles = roles
}
//Provide a default constructor for OGM
constructor() : this(applicationToken = "", profileId = "", stageName = "", showMeLaterDays = 0f,
roles = emptyArray())
}
Then use it with a repository as follows:
#Query("MATCH (n:CandidateProfile {applicationToken: {0} })
RETURN n.id as profileId, n.applicationToken as applicationToken, n.stageName as stageName, n.showMeLaterDays as showMeLaterDays, n.roles as roles;")
fun findByApplicationToken(token: String): Principal?
Note the way that node properties are returned to correspond with the class field names.
The same can be done with function results.
I'm trying to convert some Java code that uses Jackson's #JsonSubTypes annotation to manage polymorphism.
Here is the working Java code:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = Comment.class, name = "CommentNote"),
#JsonSubTypes.Type(value = Photo.class, name = "PhotoNote"),
#JsonSubTypes.Type(value = Document.class, name = "DocumentNote")
})
public abstract class Note implements Identifiable {
[...]
Here is the Kotlin code I think would be equivalent:
JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
JsonSubTypes(
JsonSubTypes.Type(value = javaClass<Comment>(), name = "CommentNote"),
JsonSubTypes.Type(value = javaClass<Photo>(), name = "PhotoNote"),
JsonSubTypes.Type(value = javaClass<Document>(), name = "DocumentNote")
)
abstract class Note : Identifiable {
[...]
But I get the following errors on each of the three "JsonSubTypes.Type" lines :
Kotlin: An annotation parameter must be a compile-time constant
Kotlin: Annotation class cannot be instantiated
Any idea?
I believe this has been resolved and nowadays you can write it like this:
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes(
JsonSubTypes.Type(value = Comment::class, name = "CommentNote"),
JsonSubTypes.Type(value = Photo::class, name = "PhotoNote"),
JsonSubTypes.Type(value = Document::class, name = "DocumentNote"))
interface Note
Note the missing # and class notation in the JsonSubTypes.Type.
Turns out it's a bug in the compiler, thanks for reporting it. To work around this issue, you can import JsonSubTypes.Type and use it without qualification:
import org.codehaus.jackson.annotate.JsonSubTypes.Type
JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
JsonSubTypes(
Type(value = javaClass<Comment>(), name = "CommentNote"),
Type(value = javaClass<Photo>(), name = "PhotoNote"),
Type(value = javaClass<Document>(), name = "DocumentNote")
)
abstract class Note : Identifiable {
[...]
I know this is an old question, nevertheless if someone is still searching for a solution to serialise/deserialise inherited classes in kotlin with jackson, I'd suggest using sealed classes and not using #JsonSubTypes.
I'd also suggest using include as EXISTING_PROPERTY and getting the property through a val inside the sealed class. Otherwise, if you add combined inherited objects inside an array, jackson won't be able to deserialise and will throw a com.fasterxml.jackson.databind.exc.InvalidTypeIdException.
Here is the example usage:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type")
sealed class Note{
val type = this::class.java.simpleName
}
data class Document(val text: String, ...) : Note()
this should work like a charm, including using this class inside an array!
Another big advantage of this approach is, you don't need to set anything manually. As we all know, manual operations are error prone, as you can forget to add/remove/modify in case you add or remove a sub class, modify name etc. In this approach, you neither need to have a manually carved sub type list, nor need to give a json representation of the class name manually.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
#JsonSubTypes(
JsonSubTypes.Type(Car::class, name = "car"),
JsonSubTypes.Type(Truck::class, name = "truck")
)
abstract class Vehicle(val type: String)
data class Car #JsonCreator constructor(#JsonProperty("manufacturer") val manufacturer: String) : Vehicle("car")
data class Truck #JsonCreator constructor(#JsonProperty("weight") val weight: Double) : Vehicle("truck")
#Test
public fun jacksonInheritanceKt() {
val s = "[{\"type\": \"car\", \"manufacturer\": \"audi\"}, {\"type\": \"truck\", \"weight\": 3000.0}]"
val mapper = ObjectMapper()
val vehicles = mapper.readValue(s, object : TypeReference<List<Vehicle>>() {})
println(vehicles)
}