This is my private function, it will return three types, success error or fault, and I want to test this private function.
class GrpcAuthClientInterceptor{
private def getToken(clientAuth: ClientAuthentication, format: String, provider: String, scopes: String): TokenCommandResult = {
val request = makeTokenRequest(provider, format, scopes, this.audience.asInstanceOf[String], clientAuth)
val result = new TokenCommand(request).execute()
result match {
case success: TokenCommandResult.Success => printAndSaveToken(format, success.getResponse.getOIDCTokens.getAccessToken.getValue)
case error: TokenCommandResult.Error => printError(format, error.getError.getErrorObject.getDescription)
case fault: TokenCommandResult.Fault => printError(format, fault.getException.getMessage)
}
result
}
}
This is how I test it, I tried to use reflection to do that, but I got error, how can I fix that?
java.lang.NoSuchMethodException: Interceptor.GrpcAuthClientInterceptorTest$$anon$1.getToken(com.nimbusds.oauth2.sdk.auth.ClientAuthentication, java.lang.String, java.lang.String, java.lang.String)
class GrpcAuthClientInterceptorTest {
private var serverInterceptor = null
private val grpcAuthClientInterceptor = new GrpcAuthClientInterceptor {
override var audience: Nothing = _
}
private var clientId = ""
private var provider = ""
private var clientSecret = "
private var scope = null
private var baseUrl = null
private var format = "jwt-application"
test("test") {
val getToken = this.grpcAuthClientInterceptor.getClass.getDeclaredMethod("getToken", classOf[ClientAuthentication], classOf[String], classOf[String], classOf[String]) //got error at this line
val clientSecretBasic = new ClientSecretBasic(new ClientID(clientId), new Secret(clientSecret))
val token = getToken.invoke(grpcAuthClientInterceptor, clientSecretBasic, format, provider, null)
assertTrue(token.isInstanceOf[TokenCommandResult.Success])
}
}
val theFunction = PrivateMethod[TokenCommandResult]('getToken)
val result = grpcAuthClientInterceptor invokePrivate theFunction()
When you call theFunction() in the final line of your question you need to pass it the necessary parameters. It would look something like:
val result = grpcAuthClientInterceptor invokePrivate theFunction(clientSecretBasic, format, provider, scopes)
Related
Currently I have two classes, how to transfer them to Algebraic Data Types? I think I can do something like this case class BlacklistDynamoDBUpdate(ruleName: String, whitelistedAccount, featureName: String), but how to use those method in that class?
class DynamoDBUpdateBlacklist {
private var features: Array[BlacklistDynamoDBUpdate] = _
def getFeatures = features
def setFeatures(features: Array[BlacklistDynamoDBUpdate]) = {
this.features = features
}
}
class BlacklistDynamoDBUpdate {
private var ruleName: String = _
private var whitelistedAccount: String = _
private var featureName: String = _
def getFeatureName: String = featureName
def setFeatureName(featureName: String) = {
this.featureName = featureName
}
def getRuleName: String = ruleName
def setRuleName(ruleName: String) = {
this.ruleName = ruleName
}
def getWhitelistedAccounts: String = whitelistedAccount
def setWhitelistedAccounts(whitelistedAccount: String): Unit = {
this.whitelistedAccount = whitelistedAccount
}
}
I transfer a json into scala object, json look like this
"features": [ { "featureName": "***", "ruleName": "***", "whitelistedAccounts": "***" }],
what I want is get those attributes value
If you need to parse json into idiomatic scala code then use simple case classes and library that is design to parse such jsons directly into those case classes (personally I sugest this one https://lihaoyi.com/upickle or this one https://circe.github.io/circe).
here is example code that shows how to use upickle.
import upickle.default.{ReadWriter => RW, macroRW}
final case class DynamoDBUpdateBlacklist(features:Seq[BlacklistDynamoDBUpdate])
final case class BlacklistDynamoDBUpdate(featureName:String, ruleName:String, whitelistedAccounts:String)
object DynamoDBUpdateBlacklist {
implicit val rw: RW[DynamoDBUpdateBlacklist] = macroRW
}
object BlacklistDynamoDBUpdate {
implicit val rw: RW[BlacklistDynamoDBUpdate] = macroRW
}
//use it like that
import upickle.default._
println(
read[DynamoDBUpdateBlacklist]("""
{"features":[{ "featureName": "***", "ruleName": "***", "whitelistedAccounts": "***" }]}
""")
)
//DynamoDBUpdateBlacklist(Vector(BlacklistDynamoDBUpdate(***,***,***)))
https://scalafiddle.io/sf/8eqFEfX/2
I have a case class that returns looks something like this
case class Response(
#JsonDeserialize(contentAs = classOf[java.lang.Long])
longList: List[Long] = null)
I have a customer ObjectMapper, that among other things registers DefaultScalaModule. According to https://github.com/FasterXML/jackson-module-scala/wiki/FAQ, adding #JsonDeserialize should solve the issue, but it doesn't
The issue is in my tests, and I get the following error message
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
at scala.runtime.BoxesRunTime.unboxToLong(BoxesRunTime.java:105)
Test class, list.head is what triggers the error
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ControllerTest {
#Autowired
var testRestTemplate: TestRestTemplate = _
#Autowired
var objectMapper: ObjectMapper = _
#Test
def test() : Unit = {
val response = testRestTemplate.exchange("url", HttpMethod.GET, classOf[Response])
val list = response.getBody.longList
val a = list.head
}
}
Debugging tells me that my list is actually of type $colon$colon containing Integers
I tried the example mentioned in Luanne's article The essence of Spring Data Neo4j 4 in Scala. The code can be found in the neo4j-ogm-scala repository.
package neo4j.ogm.scala.domain
import org.neo4j.ogm.annotation.GraphId;
import scala.beans.BeanProperty
import org.neo4j.ogm.annotation.NodeEntity
import org.neo4j.ogm.annotation.Relationship
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
abstract class Entity {
#GraphId
#BeanProperty
var id: Long = _
override def equals(o: Any): Boolean = o match {
case other: Entity => other.id.equals(this.id)
case _ => false
}
override def hashCode: Int = id.hashCode()
}
#NodeEntity
class Category extends Entity {
var name: String = _
def this(name: String) {
this()
this.name = name
}
}
#NodeEntity
class Ingredient extends Entity {
var name: String = _
#Relationship(`type` = "HAS_CATEGORY", direction = "OUTGOING")
var category: Category = _
#Relationship(`type` = "PAIRS_WITH", direction = "UNDIRECTED")
var pairings: Set[Pairing] = Set()
def addPairing(pairing: Pairing): Unit = {
pairing.first.pairings +(pairing)
pairing.second.pairings +(pairing)
}
def this(name: String, category: Category) {
this()
this.name = name
this.category = category
}
}
#RelationshipEntity(`type` = "PAIRS_WITH")
class Pairing extends Entity {
#StartNode
var first: Ingredient = _
#EndNode
var second: Ingredient = _
def this(first: Ingredient, second: Ingredient) {
this()
this.first = first
this.second = second
}
}
object Neo4jSessionFactory {
val sessionFactory = new SessionFactory("neo4j.ogm.scala.domain")
def getNeo4jSession(): Session = {
System.setProperty("username", "neo4j")
System.setProperty("password", "neo4j")
sessionFactory.openSession("http://localhost:7474")
}
}
object Main extends App {
val spices = new Category("Spices")
val turmeric = new Ingredient("Turmeric", spices)
val cumin = new Ingredient("Cumin", spices)
val pairing = new Pairing(turmeric, cumin)
cumin.addPairing(pairing)
val session = Neo4jSessionFactory.getNeo4jSession()
val tx: Transaction = session.beginTransaction()
try {
session.save(spices)
session.save(turmeric)
session.save(cumin)
session.save(pairing)
tx.commit()
} catch {
case e: Exception => // tx.rollback()
} finally {
// tx.commit()
}
}
The problem is that nothing gets saved to Neo4j. Can you please point out the problem in my code?
Thanks,
Manoj.
Scala’s Long is an instance of a Value class. Value classes were explicitly introduced to avoid allocating runtime objects. At the JVM level therefore Scala's Long is equivalent to Java’s primitive long which is why it has the primitive type signature J. It cannot be therefore be null, and should not be used as a graphId. Although Scala mostly will do auto-boxing between its own Long and Java’s Long class, this doesn’t apply to declarations, only to operations on those objects.
The #GraphId isn't being picked up on your entities. I have zero knowledge of Scala but it looks like the scala long isn't liked much by the OGM; var id: java.lang.Long = _ works fine.
I have the following sample code :
package models
import java.util.concurrent.atomic.AtomicInteger
import scala.collection.mutable.ArrayBuffer
case class Task(id: Int, label: String)
object Task {
private val buffer = new ArrayBuffer[Task]
private val incrementer = new AtomicInteger()
def all(): List[Task] = buffer.toList
def create(label: String): Int = {
val newId = incrementer.incrementAndGet()
buffer += new Task(newId, label)
newId
}
def delete(id: Int): Boolean = {
// TODO : add code
}
}
In method delete I need to find a Task that has id equal to the parameter id and if one is found I need to remove it from the collection and return true from the method. Otherwise (if none is found) I should just return false.
I know how to do this in an imperative language such as C# or Java but Scala stumps me..
PS : The code is strictly used to understand the language and the platform, it sucks too much to be pushed in production. Don't worry.
This is one possible solution, however in this case I think it's also possible to switch to var + immutable ArrayBuffer and use filter. Also note that this code is not thread safe
import java.util.concurrent.atomic.AtomicInteger
import scala.collection.mutable.ArrayBuffer
case class Task(id: Int, label: String)
object Task {
private val buffer = new ArrayBuffer[Task]
private val incrementer = new AtomicInteger()
def all(): List[Task] = buffer.toList
def create(label: String): Int = {
val newId = incrementer.incrementAndGet()
buffer.append(Task(newId, label))
newId
}
def delete(id: Int): Boolean = {
buffer.
find(_.id == id). // find task by id
map(buffer -= _). // remove it from buffer
exists(_ => true) // the same as: map(_ => true).getOrElse(false)
}
}
val id1 = Task.create("aaa")
val id2 = Task.create("bbb")
println(s"Id1 = $id1 Id2 = $id2")
println(s"All = ${Task.all()}")
val deleted = Task.delete(id1)
println(s"Deleted = $deleted")
println(s"All = ${Task.all()}")
println(s"Not Deleted = ${Task.delete(123)}")
I am writing a module for the Play Framework. In part of my module I have the following code
abstract class SecurityFiltering extends GlobalSettings{
override def onRequestReceived(request: RequestHeader) = {
play.Logger.debug("onRequestReceived: " + request)
super.onRequestReceived(request)
}
override def doFilter(next: RequestHeader => Handler): (RequestHeader => Handler) = {
request => {
play.Logger.debug("doFilter: " + request)
super.doFilter(next)(request)
}
}
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
play.Logger.debug("onRouteRequest: " + request)
super.onRouteRequest(request)
}
}
In the doFilter method I am able to determine the following useful information
ROUTE_PATTERN = /x/$name<[^/]+>/$age<[^/]+>
ROUTE_CONTROLLER = controllers.Application
ROUTE_ACTION_METHOD = tester
ROUTE_VERB = GET
path = /x/hello
What I need in addition to this is the values for the named parts of the URL before the QueryString. So given the following route in my test application I need to retrieve Name=Pete and Age=41
localhost:9000/x/Pete/41
There is surely some code in the Play Framework which already does this but I am unable to find it. Can someone suggest how I achieve this goal, or point me at which Play class extracts these values?
package models.com.encentral.tattara.web.util;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RouteExtractor {
//something like "/foo/$id<[^/]+>/edit/$james<[^/]+>"
private String routePattern;
private String path;
//something like /$id<[^/]+>
private static final String INDEX_PATTERN = "\\$(.+?)\\<\\[\\^\\/\\]\\+\\>";
public RouteExtractor(String routePattern, String path) {
this.routePattern = routePattern;
this.path = path;
}
private Map<Integer, String> extractPositions() {
Pattern pattern = Pattern.compile(INDEX_PATTERN);
Matcher matcher = pattern.matcher(this.routePattern);
Map<Integer, String> results = new HashMap<>();
int index = 0;
while (matcher.find()) {
results.put(index++, matcher.group(1));
}
return results;
}
private String replaceRoutePatternWithGroup() {
Pattern pattern = Pattern.compile(INDEX_PATTERN);
Matcher matcher = pattern.matcher(this.routePattern);
return matcher.replaceAll("([^/]+)");
}
public Map<String, String> extract() {
Pattern pattern = Pattern.compile(this.replaceRoutePatternWithGroup());
Matcher matcher = pattern.matcher(this.path);
final Map<String, String> results = new HashMap<>();
if (matcher.find()) {
this.extractPositions().entrySet().stream().forEach(s -> {
results.put(s.getValue(), matcher.group(s.getKey() + 1));
});
}
return results;
}
}
As per this GitHub issue response via JRoper
onRequestReceived is the thing that does the routing and tags the request, so of course it's not going to have any of the routing information when it's first invoked, only after it's invoked.
val p = """\$([^<]+)<([^>]+)>""".r
override def onRequestReceived(request: RequestHeader) = {
val (taggedRequest, handler) = super.onRequestReceived(request)
val pattern = taggedRequest.tags("ROUTE_PATTERN")
val paramNames = p.findAllMatchIn(pattern).map(m => m.group(1)).toList
val pathRegex = ("^" + p.replaceAllIn(pattern, m => "(" + m.group(2) + ")") + "$").r
val paramValues = pathRegex.findFirstMatchIn(request.path).get.subgroups
val params: Map[String, String] = paramNames.zip(paramValues).toMap
// ^ your params map, will be Map("name" -> "Pete", "age" -> "41")
(taggedRequest, handler)
}
That said, there are usually better, more typesafe ways to achieve whatever you're trying to achieve. If you depend on there being specific parameters in the URL, then a filter is not the right thing, because filters apply to all requests, whether they have those parameters or not. Rather, you should probably be using action composition or a custom action builder, like so:
case class MyAction(name: String, age: Int) extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
// Do your filtering here, you have access to both the name and age above
block(request)
}
}
def foo(name: String, age: Int) = MyAction(name, age) { request =>
Ok("Hello world")
}
def bar(name: String, age: Int) = MyAction(name, age).async { request =>
Future.successful(Ok("Hello world"))
}