Why the lines are crossed out and the error where the dot is I don't understand
package com.ggenius.whattowearkotlin.data.network
import android.content.Context
import android.net.ConnectivityManager
import com.ggenius.whattowearkotlin.internal.NoConnectivityException
import okhttp3.Interceptor
import okhttp3.Response
class ConnectivityInterceptorImpl(
context: Context?
) : ConnectivityInterceptor {
private val appContext = context.applicationContext
override fun intercept(chain: Interceptor.Chain): Response {
if (!isOnline())
throw NoConnectivityException()
return chain.proceed(chain.request())
}
private fun isOnline() : Boolean {
val connectivityManager = appContext.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
}
Check screenshot
enter image description here
This line is crossed out
val networkInfo = connectivityManager.activeNetworkInfo
Because the getActiveNetworkInfo() method is deprecated according to their API
https://developer.android.com/reference/android/net/ConnectivityManager#getActiveNetworkInfo()
Why the lines are crossed out?
The lines are crossed out because they are Deprecated. In Android Studio by default the deprecated use of functions, classes, variables etc. are styled as strikeout. You want to know why? It's because by default settings it's set as so. Here is Screenshot
Why the error where the dot is I don't understand?
The context.applicationContext is showing error because your context is nullable. Whenever you define your variable with Type followed by ? is nullable in Kotlin.
As you passing context: Context?, so context is nullable. To access nullable objects properties or methods you need to use objectName followed by ?. This prevents the NullPointerException that makes Kotlin null safe.
In you example you need to do;
private val appContext = context?.applicationContext
// Note that appContext will also be nullable.
Further Reading
Related
I am using blc.version 5.1.5-GA.
When adding targeted products to a product group, the listgrid only displays defaultSku.name. I would like to add additional information to the listgrid.
Here's the relevant entity definition:
#OneToMany(targetEntity = ProductProductGroupXrefImpl.class, mappedBy = "productGroup",
cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region="blProducts")
#BatchSize(size = 50)
#AdminPresentationAdornedTargetCollection(friendlyName = "ProductGroup_Products",
group = GroupName.Details, order = 3000,
joinEntityClass = "com.broadleafcommerce.merchandisinggroup.domain.ProductProductGroupXrefImpl",
targetObjectProperty = "product",
parentObjectProperty = "productGroup",
gridVisibleFields = {"defaultSku.name"})
protected List<ProductProductGroupXref> productXrefs = new ArrayList<>();
Here's some things I've tried with no success, each <mo:field> block is a separate thing I tried:
<mo:overrideItem ceilingEntity="org.broadleafcommerce.core.catalog.domain.ProductGroupImpl">
<mo:field name="defaultSku.ean, defaultSku.name">
<mo:gridVisibleField value="productXrefs"/>
</mo:field>
<mo:field name="productXrefs">
<mo:gridVisibleField value="defaultSku.name, defaultSku.ean"/>
</mo:field>
<mo:field name="defaultSku.ean">
<mo:gridVisibleField value="productXrefs"/>
</mo:field>
<mo:field name="productXrefs">
<mo:gridVisibleField value="defaultSku.ean"/>
</mo:field>
</mo:overrideItem>
I was restarting my tomcat server each time to ensure the changes were actually being loaded. Is there anything I can debug into and inspect in order to confirm this?
Someone had a similar question and he was never able to get XML overriding working. This question also needs an answer: How to override the #AdminPresentation for existing attributes.
I believe the correct format would be:
<mo:overrideItem ceilingEntity="com.broadleafcommerce.merchandisinggroup.domain.ProductGroup">
<mo:field name="productXrefs">
<mo:gridVisibleField value="defaultSku.name"/>
<mo:gridVisibleField value="defaultSku.ean"/>
</mo:field>
</mo:overrideItem>
Note that the ceilingEntity is the interface for product group, not the Impl.
KeeperofDusk's answer technically answered the original question so I accepted it, but the listgrid still wasn't displaying additional gridVisibleFields. It turns out I had the wrong package name in the ceilingEntity attribute.
In my version of blc, the package for ProductGroup is in com.broadleafcommerce.merchandisinggroup.domain, not org.broadleafcommerce.core.catalog.domain.
I debugged into AbstractFieldMetadataProvider#getTargetedOverride.
protected Map<String, MetadataOverride> getTargetedOverride(DynamicEntityDao dynamicEntityDao, String configurationKey, String ceilingEntityFullyQualifiedClassname) {
if (metadataOverrides != null && (configurationKey != null || ceilingEntityFullyQualifiedClassname != null)) {
if (metadataOverrides.containsKey(configurationKey)) {
return metadataOverrides.get(configurationKey);
}
if (metadataOverrides.containsKey(ceilingEntityFullyQualifiedClassname)) {
return metadataOverrides.get(ceilingEntityFullyQualifiedClassname);
}
Class<?> test;
try {
test = Class.forName(ceilingEntityFullyQualifiedClassname);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (test.isInterface()) {
//if it's an interface, get the least derive polymorphic concrete implementation
Class<?>[] types = dynamicEntityDao.getAllPolymorphicEntitiesFromCeiling(test);
return metadataOverrides.get(types[types.length-1].getName());
} else {
//if it's a concrete implementation, try the interfaces
Class<?>[] types = test.getInterfaces();
for (Class<?> type : types) {
if (metadataOverrides.containsKey(type.getName())) {
return metadataOverrides.get(type.getName());
}
}
}
}
return null;
}
On this exact line: return metadataOverrides.get(types[types.length-1].getName()); I was always getting null. Proper behavior is that this line should return a LinkedHashMap of the field and its FieldMetadataOverrides.
The types[types.length-1].getName() should resolve to the fully qualified classname for the target ceiling entity. I tried manually evaluating that line in my IDE but kept getting null. At this point I still haven't realized the wrong fully qualified classname was getting passed in.
Then I tried debugging into the controller endpoint in AdminBasicEntityController.
#RequestMapping(value = "/{id}/{collectionField:.*}/add", method = RequestMethod.GET)
public String showAddCollectionItem(HttpServletRequest request, HttpServletResponse response, Model model,
#PathVariable Map<String, String> pathVars,
#PathVariable(value = "id") String id,
#PathVariable(value = "collectionField") String collectionField,
#RequestParam MultiValueMap<String, String> requestParams) throws Exception {
String sectionKey = getSectionKey(pathVars);
String mainClassName = getClassNameForSection(sectionKey);
List<SectionCrumb> sectionCrumbs = getSectionCrumbs(request, sectionKey, id);
ClassMetadata mainMetadata = service.getClassMetadata(getSectionPersistencePackageRequest(mainClassName,
sectionCrumbs, pathVars)).getDynamicResultSet().getClassMetaData();
Property collectionProperty = mainMetadata.getPMap().get(collectionField);
FieldMetadata md = collectionProperty.getMetadata();
It turns out BLC_ADMIN_SECTION associates a section key with a fully qualified classname which is used to resolve the metadata for the entity. I thought the problem was that the wrong fully qualified classname was entered into the ceiling_entity column, so I changed it to org.broadleafcommerce.core.catalog.domain.ProductGroup, which didn't solve the problem. That also makes no sense, because I don't think any information about ProductGroup would render in that admin page if that were the case.
Finally I went to check if that fully qualified classname even exists, and that's when I realized I went on a wild goose chase for 10 hours.
The lesson learned for future googlers is to use auto-complete.
I am trying to figure out if I can work with Kotlin and Spark,
and use the former's data classes instead of Scala's case classes.
I have the following data class:
data class Transaction(var context: String = "", var epoch: Long = -1L, var items: HashSet<String> = HashSet()) :
Serializable {
companion object {
#JvmStatic
private val serialVersionUID = 1L
}
}
And the relevant part of the main routine looks like this:
val transactionEncoder = Encoders.bean(Transaction::class.java)
val transactions = inputDataset
.groupByKey(KeyExtractor(), KeyExtractor.getKeyEncoder())
.mapGroups(TransactionCreator(), transactionEncoder)
.collectAsList()
transactions.forEach { println("collected Transaction=$it") }
With TransactionCreator defined as:
class TransactionCreator : MapGroupsFunction<Tuple2<String, Timestamp>, Row, Transaction> {
companion object {
#JvmStatic
private val serialVersionUID = 1L
}
override fun call(key: Tuple2<String, Timestamp>, values: MutableIterator<Row>): Transaction {
val seq = generateSequence { if (values.hasNext()) values.next().getString(2) else null }
val items = seq.toCollection(HashSet())
return Transaction(key._1, key._2.time, items).also { println("inside call Transaction=$it") }
}
}
However, I think I'm running into some sort of serialization problem,
because the set ends up empty after collection.
I see the following output:
inside call Transaction=Transaction(context=context1, epoch=1000, items=[c])
inside call Transaction=Transaction(context=context1, epoch=0, items=[a, b])
collected Transaction=Transaction(context=context1, epoch=0, items=[])
collected Transaction=Transaction(context=context1, epoch=1000, items=[])
I've tried a custom KryoRegistrator to see if it was a problem with Kotlin's HashSet:
class MyRegistrator : KryoRegistrator {
override fun registerClasses(kryo: Kryo) {
kryo.register(HashSet::class.java, JavaSerializer()) // kotlin's HashSet
}
}
But it doesn't seem to help.
Any other ideas?
Full code here.
It does seem to be a serialization issue.
The documentation of Encoders.bean states (Spark v2.4.0):
collection types: only array and java.util.List currently, map support is in progress
Porting the Transaction data class to Java and changing items to a java.util.List seems to help.
I'm running into a problem with GroovyScriptEngine - it seems not to be able to work with inner classes. Anyone know whether there's some limitation in GroovyScriptEngine or a workaround?
I have a directory with these two files:
// MyClass.groovy
public class MyClass {
MyOuter m1;
MyOuter.MyInner m2;
}
and
// MyOuter.groovy
public class MyOuter {
public static class MyInner {}
}
I have a following test class:
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import groovy.util.GroovyScriptEngine;
public class TestGroovyScriptEngine {
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
final File myGroovySourceDir = new File("C:/MyGroovySourceDir");
final URL[] urls = { myGroovySourceDir.toURL() };
GroovyScriptEngine groovyScriptEngine = new GroovyScriptEngine(urls,
Thread.currentThread().getContextClassLoader());
Class<?> clazz = groovyScriptEngine.getGroovyClassLoader().loadClass("MyClass");
}
}
When I run it I get the following compilation error:
Exception in thread "main" org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
C:\MyGroovySourceDir\MyClass.groovy: 3: unable to resolve class MyOuter.MyInner
# line 3, column 2.
MyOuter.MyInner m2;
^
1 error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:311)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:983)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:633)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:582)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:354)
at groovy.lang.GroovyClassLoader.access$300(GroovyClassLoader.java:87)
at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:323)
at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:320)
at org.codehaus.groovy.runtime.memoize.ConcurrentCommonCache.getAndPut(ConcurrentCommonCache.java:147)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:318)
at groovy.util.GroovyScriptEngine$ScriptClassLoader.doParseClass(GroovyScriptEngine.java:248)
at groovy.util.GroovyScriptEngine$ScriptClassLoader.parseClass(GroovyScriptEngine.java:235)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:307)
at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:811)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:767)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:836)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:824)
I would have expected a "clean compile", but the inner class seems to be causing problems.
My groovy classes compile fine at the command line using groovyc, or in Eclipse.
You have faced an edge case here. To clarify what happens let's define the initial conditions:
you have a Java (or Groovy) class that gets executed inside JVM
you have two Groovy classes that get loaded outside of the JVM
The problem you have described does not exist if you put these two Groovy classes inside the same path you execute your Java class from - in this case IDE takes care to compile these Groovy classes and put them to the classpath of a JVM that gets started to run your Java test class.
But this is not your case and you are trying to load these two Groovy classes outside the running JVM using GroovyClassLoader (which extends URLClassLoader btw). I will try to explain in the simplest possible words what happened that adding field of type MyOuter does not throw any compilation error, but MyOuter.MyInner does.
When you execute:
Class<?> clazz = groovyScriptEngine.getGroovyClassLoader().loadClass("MyClass");
Groovy class loader goes to script file lookup part, because it was not able to find MyClass in the current classpath. This is the part responsible for it:
// at this point the loading from a parent loader failed
// and we want to recompile if needed.
if (lookupScriptFiles) {
// try groovy file
try {
// check if recompilation already happened.
final Class classCacheEntry = getClassCacheEntry(name);
if (classCacheEntry != cls) return classCacheEntry;
URL source = resourceLoader.loadGroovySource(name);
// if recompilation fails, we want cls==null
Class oldClass = cls;
cls = null;
cls = recompile(source, name, oldClass);
} catch (IOException ioe) {
last = new ClassNotFoundException("IOException while opening groovy source: " + name, ioe);
} finally {
if (cls == null) {
removeClassCacheEntry(name);
} else {
setClassCacheEntry(cls);
}
}
}
Source: src/main/groovy/lang/GroovyClassLoader.java#L733-L753
Here URL source = resourceLoader.loadGroovySource(name); it loads the full file URL to the source file and here cls = recompile(source, name, oldClass); it executes class compilation.
There are several phases involved in Groovy class compilation. One of them is Phase.SEMANTIC_ANALYSIS which analyses class fields and their types for instance. At this point ClassCodeVisitorSupport executes visitClass(ClassNode node) for MyClass class and following line
node.visitContents(this);
starts class contents processing. If we take a look at the source code of this method:
public void visitContents(GroovyClassVisitor visitor) {
// now let's visit the contents of the class
for (PropertyNode pn : getProperties()) {
visitor.visitProperty(pn);
}
for (FieldNode fn : getFields()) {
visitor.visitField(fn);
}
for (ConstructorNode cn : getDeclaredConstructors()) {
visitor.visitConstructor(cn);
}
for (MethodNode mn : getMethods()) {
visitor.visitMethod(mn);
}
}
Source: src/main/org/codehaus/groovy/ast/ClassNode.java#L1066-L108
we will see that it analyses and process class properties, fields, constructors and methods. At this phase it resolves all types defined for these elements. It sees that there are two properties m1 and m2 with types MyOuter and MyOuter.MyInner accordingly, and it executes visitor.visitProperty(pn); for them. This method executes the one we are looking for - resolve()
private boolean resolve(ClassNode type, boolean testModuleImports, boolean testDefaultImports, boolean testStaticInnerClasses) {
resolveGenericsTypes(type.getGenericsTypes());
if (type.isResolved() || type.isPrimaryClassNode()) return true;
if (type.isArray()) {
ClassNode element = type.getComponentType();
boolean resolved = resolve(element, testModuleImports, testDefaultImports, testStaticInnerClasses);
if (resolved) {
ClassNode cn = element.makeArray();
type.setRedirect(cn);
}
return resolved;
}
// test if vanilla name is current class name
if (currentClass == type) return true;
String typeName = type.getName();
if (genericParameterNames.get(typeName) != null) {
GenericsType gt = genericParameterNames.get(typeName);
type.setRedirect(gt.getType());
type.setGenericsTypes(new GenericsType[]{ gt });
type.setGenericsPlaceHolder(true);
return true;
}
if (currentClass.getNameWithoutPackage().equals(typeName)) {
type.setRedirect(currentClass);
return true;
}
return resolveNestedClass(type) ||
resolveFromModule(type, testModuleImports) ||
resolveFromCompileUnit(type) ||
resolveFromDefaultImports(type, testDefaultImports) ||
resolveFromStaticInnerClasses(type, testStaticInnerClasses) ||
resolveToOuter(type);
}
Source: src/main/org/codehaus/groovy/control/ResolveVisitor.java#L343-L378
This method gets executed for both MyOuter and MyOuter.MyInner classes. It is worth mentioning that class resolving mechanism only checks if given class is available in the classpath and it does not load or parse any classes. That is why MyOuter gets recognized when this method reaches resolveToOuter(type). If we take a quick look at its source code we will understand why it works for this class:
private boolean resolveToOuter(ClassNode type) {
String name = type.getName();
// We do not need to check instances of LowerCaseClass
// to be a Class, because unless there was an import for
// for this we do not lookup these cases. This was a decision
// made on the mailing list. To ensure we will not visit this
// method again we set a NO_CLASS for this name
if (type instanceof LowerCaseClass) {
classNodeResolver.cacheClass(name, ClassNodeResolver.NO_CLASS);
return false;
}
if (currentClass.getModule().hasPackageName() && name.indexOf('.') == -1) return false;
LookupResult lr = null;
lr = classNodeResolver.resolveName(name, compilationUnit);
if (lr!=null) {
if (lr.isSourceUnit()) {
SourceUnit su = lr.getSourceUnit();
currentClass.getCompileUnit().addClassNodeToCompile(type, su);
} else {
type.setRedirect(lr.getClassNode());
}
return true;
}
return false;
}
Source: src/main/org/codehaus/groovy/control/ResolveVisitor.java#L725-L751
When Groovy class loader tries to resolve MyOuter type name it reaches
lr = classNodeResolver.resolveName(name, compilationUnit);
which locates script with a name MyOuter.groovy and it creates a SourceUnit object associated with this script file name. It is simply something like saying "OK, this class is not in my classpath at the moment, but there is a source file I can see that once compiled it will provide a valid type of name MyOuter". This is why it finally reaches:
currentClass.getCompileUnit().addClassNodeToCompile(type, su);
where currentClass is an object associated with MyClass type - it adds this source unit to MyClass compilation unit, so it gets compiled with the MyClass class. And this is the point where resolving
MyOuter m1
class property ends.
In the next step it picks MyOuter.MyInner m2 property and it tries to resolve its type. Keep in mind - MyOuter got resolved correctly, but it didn't get loaded to the classpath, so it's static inner class does not exist in any scope, yet. It goes through the same resolving strategies as MyOuter, but any of them works for MyOuter.MyInner class. And this is why ResolveVisitor.resolveOrFail() eventually throws this compilation exception.
Workaround
OK, so we know what happens, but is there anything we can do about it? Luckily, there is a workaround for this problem. You can run your program and load MyClass successfully only if you load MyOuter class to Groovy script engine first:
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import groovy.util.GroovyScriptEngine;
public class TestGroovyScriptEngine {
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
final File myGroovySourceDir = new File("C:/MyGroovySourceDir");
final URL[] urls = { myGroovySourceDir.toURL() };
GroovyScriptEngine groovyScriptEngine = new GroovyScriptEngine(urls,
Thread.currentThread().getContextClassLoader());
groovyScriptEngine.getGroovyClassLoader().loadClass("MyOuter");
Class<?> clazz = groovyScriptEngine.getGroovyClassLoader().loadClass("MyClass");
}
}
Why does it work? Well, semantic analysis of MyOuter class does not cause any problems, because all types are known at this stage. This is why loading MyOuter class succeeds and it results in Groovy script engine instance knows what MyOuter and MyOuter.MyInner types are. So when you next load MyClass from the same Groovy script engine it will apply different resolving strategy - it will find both classes available to the current compilation unit and it wont have to resolve MyOuter class based on its Groovy script file.
Debugging
If you want to examine this use case better it is worth to run a debugger and see analyze what happens at the runtime. You can create a breakpoint at line 357 of ResolveVisitor.java file for instance, to see described scenario in action. Keep in mind one thing though - resolveFromDefaultImports(type, testDefaultImports) will try to lookup MyClass and MyOuter classes by applying default packages like java.util, java.io, groovy.lang etc. This resolve strategy kicks in before resolveToOuter(type) so you have to patiently jump through them. But it is worth it to see and get a better understanding about how things work. Hope it helps!
It seems that setting a default value for a class property, is not honored by #Builder.
#Test
void test() {
assert Foo.builder().build().getProp() != null // fail
}
#Builder
class Foo {
Map prop = [:]
}
I'll probably fix this by overriding the build method but how?
Not really sure about the implementation of builder() method of #Builder.
I believe you need to initialize the properties / members of the class, then do .build() to create the instance of the class.
Here is the example:
import groovy.transform.builder.Builder
#Builder
class Foo {
Map prop
}
def map = [a:1, b:2]
def f = Foo.builder().prop(map).build()
assert map == f.prop // or you can use f.getProp()
You can quickly try it online Demo
If you notice, the demo example shows how you can initialize multiple properties while building the object.
My code as below, refering to the solution in https://stackoverflow.com/a/30308199/3286489
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.*
class SimpleClassTest {
private fun <T> anyObject(): T {
Mockito.anyObject<T>()
return uninitialized()
}
private fun <T> uninitialized(): T = null as T
lateinit var simpleObject: SimpleClass
#Mock lateinit var injectedObject: InjectedClass
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
#Test
fun testSimpleFunction() {
simpleObject = SimpleClass(injectedObject)
verify(injectedObject).settingDependentObject(anyObject())
}
}
I still have the below error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method my.package.InjectedClass.settingDependentObject, parameter dependentObject
Did I miss anything?
UPDATED
Below is the code tested (simplest form and working)
class SimpleClass(val injectedClass: InjectedClass) {
fun simpleFunction() {
injectedClass.settingDependentObject(DependentClass(Response.Builder().build()))
}
}
open class DependentClass(response: Response) {
}
open class InjectedClass() {
lateinit var dependentObject: DependentClass
fun settingDependentObject(dependentObject: DependentClass) {
this.dependentObject = dependentObject
}
}
By default Kotlin classes and members are final. Mockito cannot mock final classes or methods.
Thus when you write:
verify(injectedObject).settingDependentObject(anyObject())
the real implementation is called which requires non null argument.
To fix that either open your class and method or, even better, change SimpleClass to accept an interface as its constructor argument and mock the interface instead.
There is a project specifically to help deal with Kotlin "closed by default" in unit testing with Mockito. For JUNIT, you can use the kotlin-testrunner which is an easy way to make any Kotlin test automatically open up classes for testing as they are loaded by the classloader. Usage is simple, just add one annotation of #RunWith(KotlinTestRunner::class), for example:
#RunWith(KotlinTestRunner::class)
class MyKotlinTestclass {
#Test
fun test() {
...
}
}
This is thoroughly covered in the article Never say final: mocking Kotlin classes in unit tests
This covers your use case in an automatic way by allowing all classes to be mocked that otherwise would not be allowed.
I ran into the same issue with Mockito when using RETURNS_DEEP_STUBS. It seems like nulls are still returned for nested objects, even when using the kotlin-allopen plugin.
Please check out and comment on this issue on Mockito if you're having the same problem.
You can use this function instead
inline fun <reified T : Any> any(): T = Mockito.any(T::class.java) ?: T::class.java.newInstance()